diff --git a/pom.xml b/pom.xml index a7efcf4c5..923889ae5 100644 --- a/pom.xml +++ b/pom.xml @@ -1,17 +1,27 @@ - + 4.0.0 com.sk89q worldedit - 5.7-SNAPSHOT + 6.0.0-SNAPSHOT jar - - + + + + UTF-8 + + + + WorldEdit 2010 http://wiki.sk89q.com/wiki/WorldEdit - A voxel map editor for Minecraft with tools for adventure map designers, - server administrators, and anyone who enjoys building massive structures. - + An in-game voxel map editor for Minecraft. + GNU General Public License 2.0 @@ -26,36 +36,44 @@ License on all new contributions - + YouTrack http://youtrack.sk89q.com - + - Jenkins - http://build.sk89q.com + TeamCity + http://builds.enginehub.org - + scm:git:git://github.com/sk89q/worldedit.git scm:git:git@github.com:sk89q/worldedit.git https://github.com/sk89q/worldedit master - + Developer Discussion https://groups.google.com/d/forum/sk-dev-discuss - + + + sk89q-docs-upload ftp://sk89q-maven-deploy/worldedit/ + + maven.sk89q.com http://maven.sk89q.com/artifactory/libs-release-local @@ -65,91 +83,89 @@ http://maven.sk89q.com/artifactory/libs-snapshot-local - - - UTF-8 - - + + + - sk89q-repo + maven.sk89q.com http://maven.sk89q.com/repo/ - - bukkit-repo - http://repo.bukkit.org/content/groups/public - - + - + + de.schlichtherle truezip 6.8.3 - compile + compile jar - - + + + rhino js 1.7R2 - compile + compile jar - - - com.sk89q - jchronic - 0.2.4a - compile - jar - - - - - com.sk89q - dummypermscompat - 1.7 - compile - jar - true - - - org.bukkit - bukkit - 1.7.2-R0.2 - compile + + + org.yaml + snakeyaml + 1.9 jar + compile true - - - org.bukkit - craftbukkit - 1.7.5-R0.1-SNAPSHOT - compile + + + + com.google.guava + guava + 10.0.1 + compile jar - true - - + + + + com.sk89q + jchronic + 0.2.4a + compile + jar + + + + org.mockito mockito-core 1.9.0-rc1 test jar - - + + + install ${basedir}/src/main/java/ - + + org.apache.maven.wagon wagon-ftp @@ -157,34 +173,29 @@ - - - . - true - ${basedir}/src/main/resources/ - - plugin.yml - - - - defaults/ - true - ${basedir}/src/main/resources/ - - config.yml - - - - nmsblocks/ - false - ${basedir}/src/main/resources/nmsblocks/ - - *.class - - - - + + + org.codehaus.mojo + build-helper-maven-plugin + 1.7 + + + add-source + generate-sources + + add-source + + + + ${basedir}/src/legacy/java/ + + + + + + + org.apache.maven.plugins maven-compiler-plugin @@ -195,6 +206,7 @@ + org.apache.maven.plugins maven-jar-plugin @@ -216,6 +228,7 @@ + maven-assembly-plugin 2.2-beta-2 @@ -233,6 +246,7 @@ + org.apache.maven.plugins maven-shade-plugin @@ -254,6 +268,7 @@ + org.apache.maven.plugins maven-release-plugin @@ -265,6 +280,7 @@ + org.apache.maven.plugins maven-surefire-plugin @@ -276,12 +292,14 @@ + org.apache.maven.plugins maven-site-plugin 3.1 + org.apache.maven.plugins maven-project-info-reports-plugin @@ -295,7 +313,8 @@ - + + org.apache.maven.plugins maven-javadoc-plugin @@ -306,9 +325,141 @@ - + + + - + + + bukkit + + + true + + + + + bukkit-repo + http://repo.bukkit.org/content/groups/public + + + + + + + com.sk89q + dummypermscompat + 1.7 + compile + jar + true + + + + + org.bukkit + bukkit + 1.7.2-R0.2 + compile + jar + true + + + + + org.bukkit + craftbukkit + 1.7.5-R0.1-SNAPSHOT + compile + jar + true + + + + + + + + . + true + ${basedir}/src/bukkit/resources/ + + plugin.yml + + + + + + defaults/ + true + ${basedir}/src/bukkit/resources/ + + config.yml + + + + + + nmsblocks/ + false + ${basedir}/src/bukkit/resources/nmsblocks/ + + *.class + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.7 + + + add-bukkit-sources + generate-sources + + add-source + + + + ${basedir}/src/bukkit/java/ + + + + + add-bukkit-test-sources + generate-sources + + add-test-source + + + + ${basedir}/src/bukkit-test/java/ + + + + + + + + + + forge @@ -341,10 +492,14 @@ - + attach-docs - + @@ -360,7 +515,7 @@ - + org.apache.maven.plugins maven-javadoc-plugin @@ -377,18 +532,22 @@ - - + + spout - + spout-repo http://nexus.spout.org/content/groups/public/ - + org.spout @@ -422,7 +581,7 @@ 1.5 - add-sources + add-spout-sources generate-sources add-source diff --git a/src/test/java/com/sk89q/wepif/DinnerPermsResolverTest.java b/src/bukkit-test/java/com/sk89q/wepif/DinnerPermsResolverTest.java similarity index 100% rename from src/test/java/com/sk89q/wepif/DinnerPermsResolverTest.java rename to src/bukkit-test/java/com/sk89q/wepif/DinnerPermsResolverTest.java diff --git a/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java b/src/bukkit-test/java/com/sk89q/wepif/TestOfflinePermissible.java similarity index 100% rename from src/test/java/com/sk89q/wepif/TestOfflinePermissible.java rename to src/bukkit-test/java/com/sk89q/wepif/TestOfflinePermissible.java diff --git a/src/test/java/com/sk89q/worldedit/bukkit/BukkitWorldTest.java b/src/bukkit-test/java/com/sk89q/worldedit/bukkit/BukkitWorldTest.java similarity index 100% rename from src/test/java/com/sk89q/worldedit/bukkit/BukkitWorldTest.java rename to src/bukkit-test/java/com/sk89q/worldedit/bukkit/BukkitWorldTest.java diff --git a/src/main/java/com/sk89q/bukkit/util/CommandInfo.java b/src/bukkit/java/com/sk89q/bukkit/util/CommandInfo.java similarity index 100% rename from src/main/java/com/sk89q/bukkit/util/CommandInfo.java rename to src/bukkit/java/com/sk89q/bukkit/util/CommandInfo.java diff --git a/src/main/java/com/sk89q/bukkit/util/CommandRegistration.java b/src/bukkit/java/com/sk89q/bukkit/util/CommandRegistration.java similarity index 100% rename from src/main/java/com/sk89q/bukkit/util/CommandRegistration.java rename to src/bukkit/java/com/sk89q/bukkit/util/CommandRegistration.java diff --git a/src/main/java/com/sk89q/bukkit/util/CommandsManagerRegistration.java b/src/bukkit/java/com/sk89q/bukkit/util/CommandsManagerRegistration.java similarity index 100% rename from src/main/java/com/sk89q/bukkit/util/CommandsManagerRegistration.java rename to src/bukkit/java/com/sk89q/bukkit/util/CommandsManagerRegistration.java diff --git a/src/main/java/com/sk89q/bukkit/util/DynamicPluginCommand.java b/src/bukkit/java/com/sk89q/bukkit/util/DynamicPluginCommand.java similarity index 100% rename from src/main/java/com/sk89q/bukkit/util/DynamicPluginCommand.java rename to src/bukkit/java/com/sk89q/bukkit/util/DynamicPluginCommand.java diff --git a/src/main/java/com/sk89q/bukkit/util/DynamicPluginCommandHelpTopic.java b/src/bukkit/java/com/sk89q/bukkit/util/DynamicPluginCommandHelpTopic.java similarity index 100% rename from src/main/java/com/sk89q/bukkit/util/DynamicPluginCommandHelpTopic.java rename to src/bukkit/java/com/sk89q/bukkit/util/DynamicPluginCommandHelpTopic.java diff --git a/src/main/java/com/sk89q/bukkit/util/FallbackRegistrationListener.java b/src/bukkit/java/com/sk89q/bukkit/util/FallbackRegistrationListener.java similarity index 100% rename from src/main/java/com/sk89q/bukkit/util/FallbackRegistrationListener.java rename to src/bukkit/java/com/sk89q/bukkit/util/FallbackRegistrationListener.java diff --git a/src/main/java/com/sk89q/wepif/ConfigurationPermissionsResolver.java b/src/bukkit/java/com/sk89q/wepif/ConfigurationPermissionsResolver.java similarity index 97% rename from src/main/java/com/sk89q/wepif/ConfigurationPermissionsResolver.java rename to src/bukkit/java/com/sk89q/wepif/ConfigurationPermissionsResolver.java index de8cedcba..674e60ef9 100644 --- a/src/main/java/com/sk89q/wepif/ConfigurationPermissionsResolver.java +++ b/src/bukkit/java/com/sk89q/wepif/ConfigurationPermissionsResolver.java @@ -1,170 +1,170 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.wepif; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.sk89q.util.yaml.YAMLNode; -import com.sk89q.util.yaml.YAMLProcessor; -import org.bukkit.OfflinePlayer; - -public class ConfigurationPermissionsResolver implements PermissionsResolver { - private YAMLProcessor config; - private Map> userPermissionsCache; - private Set defaultPermissionsCache; - private Map> userGroups; - - public ConfigurationPermissionsResolver(YAMLProcessor config) { - this.config = config; - } - - public static YAMLNode generateDefaultPerms(YAMLNode section) { - section.setProperty("groups.default.permissions", new String[] { - "worldedit.reload", - "worldedit.selection", - "worlds.creative.worldedit.region"}); - section.setProperty("groups.admins.permissions", new String[] { "*" }); - section.setProperty("users.sk89q.permissions", new String[] { "worldedit" }); - section.setProperty("users.sk89q.groups", new String[] { "admins" }); - return section; - } - - public void load() { - userGroups = new HashMap>(); - userPermissionsCache = new HashMap>(); - defaultPermissionsCache = new HashSet(); - - Map> userGroupPermissions = new HashMap>(); - - List groupKeys = config.getStringList("permissions.groups", null); - - if (groupKeys != null) { - for (String key : groupKeys) { - List permissions = - config.getStringList("permissions.groups." + key + ".permissions", null); - - if (permissions.size() > 0) { - Set groupPerms = new HashSet(permissions); - userGroupPermissions.put(key, groupPerms); - - if (key.equals("default")) { - defaultPermissionsCache.addAll(permissions); - } - } - } - } - - List userKeys = config.getStringList("permissions.users", null); - - if (userKeys != null) { - for (String key : userKeys) { - Set permsCache = new HashSet(); - - List permissions = - config.getStringList("permissions.users." + key + ".permissions", null); - - if (permissions.size() > 0) { - permsCache.addAll(permissions); - } - - List groups = - config.getStringList("permissions.users." + key + ".groups", null); - groups.add("default"); - - if (groups.size() > 0) { - for (String group : groups) { - Set groupPerms = userGroupPermissions.get(group); - if (groupPerms != null) { - permsCache.addAll(groupPerms); - } - } - } - - userPermissionsCache.put(key.toLowerCase(), permsCache); - userGroups.put(key.toLowerCase(), new HashSet(groups)); - } - } - } - - public boolean hasPermission(String player, String permission) { - int dotPos = permission.lastIndexOf("."); - if (dotPos > -1) { - if (hasPermission(player, permission.substring(0, dotPos))) { - return true; - } - } - - Set perms = userPermissionsCache.get(player.toLowerCase()); - if (perms == null) { - return defaultPermissionsCache.contains(permission) - || defaultPermissionsCache.contains("*"); - } - - return perms.contains("*") || perms.contains(permission); - } - - public boolean hasPermission(String worldName, String player, String permission) { - return hasPermission(player, "worlds." + worldName + "." + permission) - || hasPermission(player, permission); - } - - public boolean inGroup(String player, String group) { - Set groups = userGroups.get(player.toLowerCase()); - if (groups == null) { - return false; - } - - return groups.contains(group); - } - - public String[] getGroups(String player) { - Set groups = userGroups.get(player.toLowerCase()); - if (groups == null) { - return new String[0]; - } - - return groups.toArray(new String[groups.size()]); - } - - public boolean hasPermission(OfflinePlayer player, String permission) { - return hasPermission(player.getName(), permission); - } - - public boolean hasPermission(String worldName, OfflinePlayer player, String permission) { - return hasPermission(worldName, player.getName(), permission); - } - - public boolean inGroup(OfflinePlayer player, String group) { - return inGroup(player.getName(), group); - } - - public String[] getGroups(OfflinePlayer player) { - return getGroups(player.getName()); - } - - public String getDetectionMessage() { - return "No known permissions plugin detected. Using configuration file for permissions."; - } - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.wepif; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.sk89q.util.yaml.YAMLNode; +import com.sk89q.util.yaml.YAMLProcessor; +import org.bukkit.OfflinePlayer; + +public class ConfigurationPermissionsResolver implements PermissionsResolver { + private YAMLProcessor config; + private Map> userPermissionsCache; + private Set defaultPermissionsCache; + private Map> userGroups; + + public ConfigurationPermissionsResolver(YAMLProcessor config) { + this.config = config; + } + + public static YAMLNode generateDefaultPerms(YAMLNode section) { + section.setProperty("groups.default.permissions", new String[] { + "worldedit.reload", + "worldedit.selection", + "worlds.creative.worldedit.region"}); + section.setProperty("groups.admins.permissions", new String[] { "*" }); + section.setProperty("users.sk89q.permissions", new String[] { "worldedit" }); + section.setProperty("users.sk89q.groups", new String[] { "admins" }); + return section; + } + + public void load() { + userGroups = new HashMap>(); + userPermissionsCache = new HashMap>(); + defaultPermissionsCache = new HashSet(); + + Map> userGroupPermissions = new HashMap>(); + + List groupKeys = config.getStringList("permissions.groups", null); + + if (groupKeys != null) { + for (String key : groupKeys) { + List permissions = + config.getStringList("permissions.groups." + key + ".permissions", null); + + if (permissions.size() > 0) { + Set groupPerms = new HashSet(permissions); + userGroupPermissions.put(key, groupPerms); + + if (key.equals("default")) { + defaultPermissionsCache.addAll(permissions); + } + } + } + } + + List userKeys = config.getStringList("permissions.users", null); + + if (userKeys != null) { + for (String key : userKeys) { + Set permsCache = new HashSet(); + + List permissions = + config.getStringList("permissions.users." + key + ".permissions", null); + + if (permissions.size() > 0) { + permsCache.addAll(permissions); + } + + List groups = + config.getStringList("permissions.users." + key + ".groups", null); + groups.add("default"); + + if (groups.size() > 0) { + for (String group : groups) { + Set groupPerms = userGroupPermissions.get(group); + if (groupPerms != null) { + permsCache.addAll(groupPerms); + } + } + } + + userPermissionsCache.put(key.toLowerCase(), permsCache); + userGroups.put(key.toLowerCase(), new HashSet(groups)); + } + } + } + + public boolean hasPermission(String player, String permission) { + int dotPos = permission.lastIndexOf("."); + if (dotPos > -1) { + if (hasPermission(player, permission.substring(0, dotPos))) { + return true; + } + } + + Set perms = userPermissionsCache.get(player.toLowerCase()); + if (perms == null) { + return defaultPermissionsCache.contains(permission) + || defaultPermissionsCache.contains("*"); + } + + return perms.contains("*") || perms.contains(permission); + } + + public boolean hasPermission(String worldName, String player, String permission) { + return hasPermission(player, "worlds." + worldName + "." + permission) + || hasPermission(player, permission); + } + + public boolean inGroup(String player, String group) { + Set groups = userGroups.get(player.toLowerCase()); + if (groups == null) { + return false; + } + + return groups.contains(group); + } + + public String[] getGroups(String player) { + Set groups = userGroups.get(player.toLowerCase()); + if (groups == null) { + return new String[0]; + } + + return groups.toArray(new String[groups.size()]); + } + + public boolean hasPermission(OfflinePlayer player, String permission) { + return hasPermission(player.getName(), permission); + } + + public boolean hasPermission(String worldName, OfflinePlayer player, String permission) { + return hasPermission(worldName, player.getName(), permission); + } + + public boolean inGroup(OfflinePlayer player, String group) { + return inGroup(player.getName(), group); + } + + public String[] getGroups(OfflinePlayer player) { + return getGroups(player.getName()); + } + + public String getDetectionMessage() { + return "No known permissions plugin detected. Using configuration file for permissions."; + } + +} diff --git a/src/main/java/com/sk89q/wepif/DinnerPermsResolver.java b/src/bukkit/java/com/sk89q/wepif/DinnerPermsResolver.java similarity index 100% rename from src/main/java/com/sk89q/wepif/DinnerPermsResolver.java rename to src/bukkit/java/com/sk89q/wepif/DinnerPermsResolver.java diff --git a/src/main/java/com/sk89q/wepif/FlatFilePermissionsResolver.java b/src/bukkit/java/com/sk89q/wepif/FlatFilePermissionsResolver.java similarity index 96% rename from src/main/java/com/sk89q/wepif/FlatFilePermissionsResolver.java rename to src/bukkit/java/com/sk89q/wepif/FlatFilePermissionsResolver.java index aca21f199..7a035bc0b 100644 --- a/src/main/java/com/sk89q/wepif/FlatFilePermissionsResolver.java +++ b/src/bukkit/java/com/sk89q/wepif/FlatFilePermissionsResolver.java @@ -1,237 +1,237 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.wepif; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.HashMap; - -import com.sk89q.util.yaml.YAMLProcessor; -import org.bukkit.OfflinePlayer; -import org.bukkit.Server; - -public class FlatFilePermissionsResolver implements PermissionsResolver { - private Map> userPermissionsCache; - private Set defaultPermissionsCache; - private Map> userGroups; - - protected File groupFile; - protected File userFile; - - public static PermissionsResolver factory(Server server, YAMLProcessor config) { - File groups = new File("perms_groups.txt"); - File users = new File("perms_users.txt"); - - if (!groups.exists() || !users.exists()) { - return null; - } - - return new FlatFilePermissionsResolver(groups, users); - } - - public FlatFilePermissionsResolver() { - this(new File("perms_groups.txt"), new File("perms_users.txt")); - } - - public FlatFilePermissionsResolver(File groupFile, File userFile) { - this.groupFile = groupFile; - this.userFile = userFile; - } - - @Deprecated - public static boolean filesExists() { - return (new File("perms_groups.txt")).exists() && (new File("perms_users.txt")).exists(); - } - - public Map> loadGroupPermissions() { - Map> userGroupPermissions = new HashMap>(); - - BufferedReader buff = null; - - try { - FileReader input = new FileReader(this.groupFile); - buff = new BufferedReader(input); - - String line; - while ((line = buff.readLine()) != null) { - line = line.trim(); - - // Blank line - if (line.length() == 0) { - continue; - } else if (line.charAt(0) == ';' || line.charAt(0) == '#') { - continue; - } - - String[] parts = line.split(":"); - - String key = parts[0]; - - if (parts.length > 1) { - String[] perms = parts[1].split(","); - - Set groupPerms = new HashSet(Arrays.asList(perms)); - userGroupPermissions.put(key, groupPerms); - } - } - } catch (IOException e) { - e.printStackTrace(); - } finally { - try { - if (buff != null) { - buff.close(); - } - } catch (IOException e2) { - } - } - - return userGroupPermissions; - } - - public void load() { - userGroups = new HashMap>(); - userPermissionsCache = new HashMap>(); - defaultPermissionsCache = new HashSet(); - - Map> userGroupPermissions = loadGroupPermissions(); - - if (userGroupPermissions.containsKey("default")) { - defaultPermissionsCache = userGroupPermissions.get("default"); - } - - BufferedReader buff = null; - - try { - FileReader input = new FileReader(this.userFile); - buff = new BufferedReader(input); - - String line; - while ((line = buff.readLine()) != null) { - Set permsCache = new HashSet(); - - line = line.trim(); - - // Blank line - if (line.length() == 0) { - continue; - } else if (line.charAt(0) == ';' || line.charAt(0) == '#') { - continue; - } - - String[] parts = line.split(":"); - - String key = parts[0]; - - if (parts.length > 1) { - String[] groups = (parts[1] + ",default").split(","); - String[] perms = parts.length > 2 ? parts[2].split(",") : new String[0]; - - permsCache.addAll(Arrays.asList(perms)); - - for (String group : groups) { - Set groupPerms = userGroupPermissions.get(group); - if (groupPerms != null) { - permsCache.addAll(groupPerms); - } - } - - userPermissionsCache.put(key.toLowerCase(), permsCache); - userGroups.put(key.toLowerCase(), new HashSet(Arrays.asList(groups))); - } - } - } catch (IOException e) { - e.printStackTrace(); - } finally { - try { - if (buff != null) { - buff.close(); - } - } catch (IOException e2) { - } - } - } - - public boolean hasPermission(String player, String permission) { - int dotPos = permission.lastIndexOf("."); - if (dotPos > -1) { - if (hasPermission(player, permission.substring(0, dotPos))) { - return true; - } - } - - Set perms = userPermissionsCache.get(player.toLowerCase()); - if (perms == null) { - return defaultPermissionsCache.contains(permission) - || defaultPermissionsCache.contains("*"); - } - - return perms.contains("*") || perms.contains(permission); - } - - public boolean hasPermission(String worldName, String player, String permission) { - return hasPermission(player, "worlds." + worldName + "." + permission) - || hasPermission(player, permission); - } - - public boolean inGroup(String player, String group) { - Set groups = userGroups.get(player.toLowerCase()); - if (groups == null) { - return false; - } - - return groups.contains(group); - } - - public String[] getGroups(String player) { - Set groups = userGroups.get(player.toLowerCase()); - if (groups == null) { - return new String[0]; - } - - return groups.toArray(new String[groups.size()]); - } - - public boolean hasPermission(OfflinePlayer player, String permission) { - return hasPermission(player.getName(), permission); - } - - public boolean hasPermission(String worldName, OfflinePlayer player, String permission) { - return hasPermission(worldName, player.getName(), permission); - } - - public boolean inGroup(OfflinePlayer player, String group) { - return inGroup(player.getName(), group); - } - - public String[] getGroups(OfflinePlayer player) { - return getGroups(player.getName()); - } - - public String getDetectionMessage() { - return "perms_groups.txt and perms_users.txt detected! Using flat file permissions."; - } - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.wepif; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.HashMap; + +import com.sk89q.util.yaml.YAMLProcessor; +import org.bukkit.OfflinePlayer; +import org.bukkit.Server; + +public class FlatFilePermissionsResolver implements PermissionsResolver { + private Map> userPermissionsCache; + private Set defaultPermissionsCache; + private Map> userGroups; + + protected File groupFile; + protected File userFile; + + public static PermissionsResolver factory(Server server, YAMLProcessor config) { + File groups = new File("perms_groups.txt"); + File users = new File("perms_users.txt"); + + if (!groups.exists() || !users.exists()) { + return null; + } + + return new FlatFilePermissionsResolver(groups, users); + } + + public FlatFilePermissionsResolver() { + this(new File("perms_groups.txt"), new File("perms_users.txt")); + } + + public FlatFilePermissionsResolver(File groupFile, File userFile) { + this.groupFile = groupFile; + this.userFile = userFile; + } + + @Deprecated + public static boolean filesExists() { + return (new File("perms_groups.txt")).exists() && (new File("perms_users.txt")).exists(); + } + + public Map> loadGroupPermissions() { + Map> userGroupPermissions = new HashMap>(); + + BufferedReader buff = null; + + try { + FileReader input = new FileReader(this.groupFile); + buff = new BufferedReader(input); + + String line; + while ((line = buff.readLine()) != null) { + line = line.trim(); + + // Blank line + if (line.length() == 0) { + continue; + } else if (line.charAt(0) == ';' || line.charAt(0) == '#') { + continue; + } + + String[] parts = line.split(":"); + + String key = parts[0]; + + if (parts.length > 1) { + String[] perms = parts[1].split(","); + + Set groupPerms = new HashSet(Arrays.asList(perms)); + userGroupPermissions.put(key, groupPerms); + } + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (buff != null) { + buff.close(); + } + } catch (IOException e2) { + } + } + + return userGroupPermissions; + } + + public void load() { + userGroups = new HashMap>(); + userPermissionsCache = new HashMap>(); + defaultPermissionsCache = new HashSet(); + + Map> userGroupPermissions = loadGroupPermissions(); + + if (userGroupPermissions.containsKey("default")) { + defaultPermissionsCache = userGroupPermissions.get("default"); + } + + BufferedReader buff = null; + + try { + FileReader input = new FileReader(this.userFile); + buff = new BufferedReader(input); + + String line; + while ((line = buff.readLine()) != null) { + Set permsCache = new HashSet(); + + line = line.trim(); + + // Blank line + if (line.length() == 0) { + continue; + } else if (line.charAt(0) == ';' || line.charAt(0) == '#') { + continue; + } + + String[] parts = line.split(":"); + + String key = parts[0]; + + if (parts.length > 1) { + String[] groups = (parts[1] + ",default").split(","); + String[] perms = parts.length > 2 ? parts[2].split(",") : new String[0]; + + permsCache.addAll(Arrays.asList(perms)); + + for (String group : groups) { + Set groupPerms = userGroupPermissions.get(group); + if (groupPerms != null) { + permsCache.addAll(groupPerms); + } + } + + userPermissionsCache.put(key.toLowerCase(), permsCache); + userGroups.put(key.toLowerCase(), new HashSet(Arrays.asList(groups))); + } + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (buff != null) { + buff.close(); + } + } catch (IOException e2) { + } + } + } + + public boolean hasPermission(String player, String permission) { + int dotPos = permission.lastIndexOf("."); + if (dotPos > -1) { + if (hasPermission(player, permission.substring(0, dotPos))) { + return true; + } + } + + Set perms = userPermissionsCache.get(player.toLowerCase()); + if (perms == null) { + return defaultPermissionsCache.contains(permission) + || defaultPermissionsCache.contains("*"); + } + + return perms.contains("*") || perms.contains(permission); + } + + public boolean hasPermission(String worldName, String player, String permission) { + return hasPermission(player, "worlds." + worldName + "." + permission) + || hasPermission(player, permission); + } + + public boolean inGroup(String player, String group) { + Set groups = userGroups.get(player.toLowerCase()); + if (groups == null) { + return false; + } + + return groups.contains(group); + } + + public String[] getGroups(String player) { + Set groups = userGroups.get(player.toLowerCase()); + if (groups == null) { + return new String[0]; + } + + return groups.toArray(new String[groups.size()]); + } + + public boolean hasPermission(OfflinePlayer player, String permission) { + return hasPermission(player.getName(), permission); + } + + public boolean hasPermission(String worldName, OfflinePlayer player, String permission) { + return hasPermission(worldName, player.getName(), permission); + } + + public boolean inGroup(OfflinePlayer player, String group) { + return inGroup(player.getName(), group); + } + + public String[] getGroups(OfflinePlayer player) { + return getGroups(player.getName()); + } + + public String getDetectionMessage() { + return "perms_groups.txt and perms_users.txt detected! Using flat file permissions."; + } + +} diff --git a/src/main/java/com/sk89q/wepif/GroupManagerResolver.java b/src/bukkit/java/com/sk89q/wepif/GroupManagerResolver.java similarity index 100% rename from src/main/java/com/sk89q/wepif/GroupManagerResolver.java rename to src/bukkit/java/com/sk89q/wepif/GroupManagerResolver.java diff --git a/src/main/java/com/sk89q/wepif/NijiPermissionsResolver.java b/src/bukkit/java/com/sk89q/wepif/NijiPermissionsResolver.java similarity index 97% rename from src/main/java/com/sk89q/wepif/NijiPermissionsResolver.java rename to src/bukkit/java/com/sk89q/wepif/NijiPermissionsResolver.java index 301c2a8ee..16d9662cc 100644 --- a/src/main/java/com/sk89q/wepif/NijiPermissionsResolver.java +++ b/src/bukkit/java/com/sk89q/wepif/NijiPermissionsResolver.java @@ -1,161 +1,161 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.wepif; - -import com.sk89q.util.yaml.YAMLProcessor; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.Server; -import org.bukkit.command.PluginCommand; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.PluginManager; -import com.nijikokun.bukkit.Permissions.Permissions; - -public class NijiPermissionsResolver implements PermissionsResolver { - private Server server; - private Permissions api; - - public static PermissionsResolver factory(Server server, YAMLProcessor config) { - PluginManager pluginManager = server.getPluginManager(); - try { - Class.forName("com.nijikokun.bukkit.Permissions.Permissions"); - } catch (ClassNotFoundException e) { - return null; - } - - Plugin plugin = pluginManager.getPlugin("Permissions"); - - // Check if plugin is loaded and has Permissions interface - if (plugin == null || !(plugin instanceof Permissions)) { - return null; - } - - // Check for fake permissions - if (config.getBoolean("ignore-nijiperms-bridges", true) && isFakeNijiPerms(plugin)) { - return null; - } - - return new NijiPermissionsResolver(server, (Permissions) plugin); - } - - public void load() { - - } - - public NijiPermissionsResolver(Server server, Permissions plugin) { - this.server = server; - this.api = plugin; - } - - @SuppressWarnings("static-access") - public boolean hasPermission(String name, String permission) { - try { - Player player = server.getPlayerExact(name); - if (player == null) return false; - try { - return api.getHandler().has(player, permission); - } catch (Throwable t) { - return api.Security.permission(player, permission); - } - } catch (Throwable t) { - t.printStackTrace(); - return false; - } - } - - public boolean hasPermission(String worldName, String name, String permission) { - try { - try { - return api.getHandler().has(worldName, name, permission); - } catch (Throwable t) { - return api.getHandler().has(server.getPlayerExact(name), permission); - } - } catch (Throwable t) { - t.printStackTrace(); - return false; - } - } - - @SuppressWarnings("static-access") - public boolean inGroup(String name, String group) { - try { - Player player = server.getPlayerExact(name); - if (player == null) return false; - try { - return api.getHandler().inGroup(player.getWorld().getName(), name, group); - } catch (Throwable t) { - return api.Security.inGroup(name, group); - } - } catch (Throwable t) { - t.printStackTrace(); - return false; - } - } - - @SuppressWarnings("static-access") - public String[] getGroups(String name) { - try { - Player player = server.getPlayerExact(name); - if (player == null) return new String[0]; - String[] groups = null; - try { - groups = api.getHandler().getGroups(player.getWorld().getName(), player.getName()); - } catch (Throwable t) { - String group = api.Security.getGroup(player.getWorld().getName(), player.getName()); - if (group != null) groups = new String[] { group }; - } - if (groups == null) { - return new String[0]; - } else { - return groups; - } - } catch (Throwable t) { - t.printStackTrace(); - return new String[0]; - } - } - - public boolean hasPermission(OfflinePlayer player, String permission) { - return hasPermission(player.getName(), permission); - } - - public boolean hasPermission(String worldName, OfflinePlayer player, String permission) { - return hasPermission(worldName, player.getName(), permission); - } - - public boolean inGroup(OfflinePlayer player, String group) { - return inGroup(player.getName(), group); - } - - public String[] getGroups(OfflinePlayer player) { - return getGroups(player.getName()); - } - - public static boolean isFakeNijiPerms(Plugin plugin) { - PluginCommand permsCommand = Bukkit.getServer().getPluginCommand("permissions"); - - return permsCommand == null || !(permsCommand.getPlugin().equals(plugin)); - } - - public String getDetectionMessage() { - return "Permissions plugin detected! Using Permissions plugin for permissions."; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.wepif; + +import com.sk89q.util.yaml.YAMLProcessor; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.Server; +import org.bukkit.command.PluginCommand; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginManager; +import com.nijikokun.bukkit.Permissions.Permissions; + +public class NijiPermissionsResolver implements PermissionsResolver { + private Server server; + private Permissions api; + + public static PermissionsResolver factory(Server server, YAMLProcessor config) { + PluginManager pluginManager = server.getPluginManager(); + try { + Class.forName("com.nijikokun.bukkit.Permissions.Permissions"); + } catch (ClassNotFoundException e) { + return null; + } + + Plugin plugin = pluginManager.getPlugin("Permissions"); + + // Check if plugin is loaded and has Permissions interface + if (plugin == null || !(plugin instanceof Permissions)) { + return null; + } + + // Check for fake permissions + if (config.getBoolean("ignore-nijiperms-bridges", true) && isFakeNijiPerms(plugin)) { + return null; + } + + return new NijiPermissionsResolver(server, (Permissions) plugin); + } + + public void load() { + + } + + public NijiPermissionsResolver(Server server, Permissions plugin) { + this.server = server; + this.api = plugin; + } + + @SuppressWarnings("static-access") + public boolean hasPermission(String name, String permission) { + try { + Player player = server.getPlayerExact(name); + if (player == null) return false; + try { + return api.getHandler().has(player, permission); + } catch (Throwable t) { + return api.Security.permission(player, permission); + } + } catch (Throwable t) { + t.printStackTrace(); + return false; + } + } + + public boolean hasPermission(String worldName, String name, String permission) { + try { + try { + return api.getHandler().has(worldName, name, permission); + } catch (Throwable t) { + return api.getHandler().has(server.getPlayerExact(name), permission); + } + } catch (Throwable t) { + t.printStackTrace(); + return false; + } + } + + @SuppressWarnings("static-access") + public boolean inGroup(String name, String group) { + try { + Player player = server.getPlayerExact(name); + if (player == null) return false; + try { + return api.getHandler().inGroup(player.getWorld().getName(), name, group); + } catch (Throwable t) { + return api.Security.inGroup(name, group); + } + } catch (Throwable t) { + t.printStackTrace(); + return false; + } + } + + @SuppressWarnings("static-access") + public String[] getGroups(String name) { + try { + Player player = server.getPlayerExact(name); + if (player == null) return new String[0]; + String[] groups = null; + try { + groups = api.getHandler().getGroups(player.getWorld().getName(), player.getName()); + } catch (Throwable t) { + String group = api.Security.getGroup(player.getWorld().getName(), player.getName()); + if (group != null) groups = new String[] { group }; + } + if (groups == null) { + return new String[0]; + } else { + return groups; + } + } catch (Throwable t) { + t.printStackTrace(); + return new String[0]; + } + } + + public boolean hasPermission(OfflinePlayer player, String permission) { + return hasPermission(player.getName(), permission); + } + + public boolean hasPermission(String worldName, OfflinePlayer player, String permission) { + return hasPermission(worldName, player.getName(), permission); + } + + public boolean inGroup(OfflinePlayer player, String group) { + return inGroup(player.getName(), group); + } + + public String[] getGroups(OfflinePlayer player) { + return getGroups(player.getName()); + } + + public static boolean isFakeNijiPerms(Plugin plugin) { + PluginCommand permsCommand = Bukkit.getServer().getPluginCommand("permissions"); + + return permsCommand == null || !(permsCommand.getPlugin().equals(plugin)); + } + + public String getDetectionMessage() { + return "Permissions plugin detected! Using Permissions plugin for permissions."; + } +} diff --git a/src/main/java/com/sk89q/wepif/PermissionsExResolver.java b/src/bukkit/java/com/sk89q/wepif/PermissionsExResolver.java similarity index 100% rename from src/main/java/com/sk89q/wepif/PermissionsExResolver.java rename to src/bukkit/java/com/sk89q/wepif/PermissionsExResolver.java diff --git a/src/main/java/com/sk89q/wepif/PermissionsProvider.java b/src/bukkit/java/com/sk89q/wepif/PermissionsProvider.java similarity index 97% rename from src/main/java/com/sk89q/wepif/PermissionsProvider.java rename to src/bukkit/java/com/sk89q/wepif/PermissionsProvider.java index 199f1580a..033f0f0e6 100644 --- a/src/main/java/com/sk89q/wepif/PermissionsProvider.java +++ b/src/bukkit/java/com/sk89q/wepif/PermissionsProvider.java @@ -1,40 +1,40 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.wepif; - -import org.bukkit.OfflinePlayer; - -public interface PermissionsProvider { - public boolean hasPermission(String name, String permission); - - public boolean hasPermission(String worldName, String name, String permission); - - public boolean inGroup(String player, String group); - - public String[] getGroups(String player); - - public boolean hasPermission(OfflinePlayer player, String permission); - - public boolean hasPermission(String worldName, OfflinePlayer player, String permission); - - public boolean inGroup(OfflinePlayer player, String group); - - public String[] getGroups(OfflinePlayer player); -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.wepif; + +import org.bukkit.OfflinePlayer; + +public interface PermissionsProvider { + public boolean hasPermission(String name, String permission); + + public boolean hasPermission(String worldName, String name, String permission); + + public boolean inGroup(String player, String group); + + public String[] getGroups(String player); + + public boolean hasPermission(OfflinePlayer player, String permission); + + public boolean hasPermission(String worldName, OfflinePlayer player, String permission); + + public boolean inGroup(OfflinePlayer player, String group); + + public String[] getGroups(OfflinePlayer player); +} diff --git a/src/main/java/com/sk89q/wepif/PermissionsResolver.java b/src/bukkit/java/com/sk89q/wepif/PermissionsResolver.java similarity index 97% rename from src/main/java/com/sk89q/wepif/PermissionsResolver.java rename to src/bukkit/java/com/sk89q/wepif/PermissionsResolver.java index dce444807..e8581a7f9 100644 --- a/src/main/java/com/sk89q/wepif/PermissionsResolver.java +++ b/src/bukkit/java/com/sk89q/wepif/PermissionsResolver.java @@ -1,26 +1,26 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.wepif; - -public interface PermissionsResolver extends PermissionsProvider { - public void load(); - - public String getDetectionMessage(); -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.wepif; + +public interface PermissionsResolver extends PermissionsProvider { + public void load(); + + public String getDetectionMessage(); +} diff --git a/src/main/java/com/sk89q/wepif/PermissionsResolverManager.java b/src/bukkit/java/com/sk89q/wepif/PermissionsResolverManager.java similarity index 97% rename from src/main/java/com/sk89q/wepif/PermissionsResolverManager.java rename to src/bukkit/java/com/sk89q/wepif/PermissionsResolverManager.java index f5ae11fb8..3cf80d2fe 100644 --- a/src/main/java/com/sk89q/wepif/PermissionsResolverManager.java +++ b/src/bukkit/java/com/sk89q/wepif/PermissionsResolverManager.java @@ -1,298 +1,298 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.wepif; - -import com.sk89q.util.yaml.YAMLFormat; -import com.sk89q.util.yaml.YAMLProcessor; -import org.bukkit.OfflinePlayer; -import org.bukkit.Server; -import org.bukkit.event.EventHandler; -import org.bukkit.event.server.PluginDisableEvent; -import org.bukkit.event.server.PluginEnableEvent; -import org.bukkit.plugin.Plugin; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.logging.Logger; - -public class PermissionsResolverManager implements PermissionsResolver { - private static final String CONFIG_HEADER = "#\r\n" + - "# WEPIF Configuration File\r\n" + - "#\r\n" + - "# This file handles permissions configuration for every plugin using WEPIF\r\n" + - "#\r\n" + - "# About editing this file:\r\n" + - "# - DO NOT USE TABS. You MUST use spaces or Bukkit will complain. If\r\n" + - "# you use an editor like Notepad++ (recommended for Windows users), you\r\n" + - "# must configure it to \"replace tabs with spaces.\" In Notepad++, this can\r\n" + - "# be changed in Settings > Preferences > Language Menu.\r\n" + - "# - Don't get rid of the indents. They are indented so some entries are\r\n" + - "# in categories (like \"enforce-single-session\" is in the \"protection\"\r\n" + - "# category.\r\n" + - "# - If you want to check the format of this file before putting it\r\n" + - "# into WEPIF, paste it into http://yaml-online-parser.appspot.com/\r\n" + - "# and see if it gives \"ERROR:\".\r\n" + - "# - Lines starting with # are comments and so they are ignored.\r\n" + - "#\r\n" + - "# About Configuration Permissions\r\n" + - "# - See http://wiki.sk89q.com/wiki/WorldEdit/Permissions/Bukkit\r\n" + - "# - Now with multiworld support (see example)\r\n" + - "\r\n"; - - private static PermissionsResolverManager instance; - - public static void initialize(Plugin plugin) { - if (!isInitialized()) { - instance = new PermissionsResolverManager(plugin); - } - } - - public static boolean isInitialized() { - return instance != null; - } - - public static PermissionsResolverManager getInstance() { - if (!isInitialized()) { - throw new WEPIFRuntimeException("WEPIF has not yet been initialized!"); - } - return instance; - } - - private Server server; - private PermissionsResolver permissionResolver; - private YAMLProcessor config; - private Logger logger = Logger.getLogger(getClass().getCanonicalName()); - private List> enabledResolvers = new ArrayList>(); - - @SuppressWarnings("unchecked") - protected Class[] availableResolvers = new Class[] { - PluginPermissionsResolver.class, - PermissionsExResolver.class, - bPermissionsResolver.class, - GroupManagerResolver.class, - NijiPermissionsResolver.class, - DinnerPermsResolver.class, - FlatFilePermissionsResolver.class - }; - - protected PermissionsResolverManager(Plugin plugin) { - this.server = plugin.getServer(); - (new ServerListener()).register(plugin); // Register the events - - loadConfig(new File("wepif.yml")); - findResolver(); - } - - public void findResolver() { - for (Class resolverClass : enabledResolvers) { - try { - Method factoryMethod = resolverClass.getMethod("factory", Server.class, YAMLProcessor.class); - - this.permissionResolver = (PermissionsResolver) factoryMethod.invoke(null, this.server, this.config); - - if (this.permissionResolver != null) { - break; - } - } catch (Throwable e) { - logger.warning("Error in factory method for " + resolverClass.getSimpleName() + ": " + e); - e.printStackTrace(); - continue; - } - } - if (permissionResolver == null) { - permissionResolver = new ConfigurationPermissionsResolver(config); - } - permissionResolver.load(); - logger.info("WEPIF: " + permissionResolver.getDetectionMessage()); - } - - public void setPluginPermissionsResolver(Plugin plugin) { - if (!(plugin instanceof PermissionsProvider)) { - return; - } - - permissionResolver = new PluginPermissionsResolver((PermissionsProvider) plugin, plugin); - logger.info("WEPIF: " + permissionResolver.getDetectionMessage()); - } - - public void load() { - findResolver(); - } - - public boolean hasPermission(String name, String permission) { - return permissionResolver.hasPermission(name, permission); - } - - public boolean hasPermission(String worldName, String name, String permission) { - return permissionResolver.hasPermission(worldName, name, permission); - } - - public boolean inGroup(String player, String group) { - return permissionResolver.inGroup(player, group); - } - - public String[] getGroups(String player) { - return permissionResolver.getGroups(player); - } - - public boolean hasPermission(OfflinePlayer player, String permission) { - return permissionResolver.hasPermission(player, permission); - } - - public boolean hasPermission(String worldName, OfflinePlayer player, String permission) { - return permissionResolver.hasPermission(worldName, player, permission); - } - - public boolean inGroup(OfflinePlayer player, String group) { - return permissionResolver.inGroup(player, group); - } - - public String[] getGroups(OfflinePlayer player) { - return permissionResolver.getGroups(player); - } - - public String getDetectionMessage() { - return "Using WEPIF for permissions"; - } - - private boolean loadConfig(File file) { - boolean isUpdated = false; - if (!file.exists()) { - try { - file.createNewFile(); - } catch (IOException e) { - e.printStackTrace(); - } - } - config = new YAMLProcessor(file, false, YAMLFormat.EXTENDED); - try { - config.load(); - } catch (IOException e) { - logger.severe("Error loading WEPIF Config: " + e); - e.printStackTrace(); - } - List keys = config.getKeys(null); - config.setHeader(CONFIG_HEADER); - - if (!keys.contains("ignore-nijiperms-bridges")) { - config.setProperty("ignore-nijiperms-bridges", true); - isUpdated = true; - } - - if (!keys.contains("resolvers")) { - //List resolverKeys = config.getKeys("resolvers"); - List resolvers = new ArrayList(); - for (Class clazz : availableResolvers) { - resolvers.add(clazz.getSimpleName()); - } - enabledResolvers.addAll(Arrays.asList(availableResolvers)); - config.setProperty("resolvers.enabled", resolvers); - isUpdated = true; - } else { - List disabledResolvers = config.getStringList("resolvers.disabled", new ArrayList()); - List stagedEnabled = config.getStringList("resolvers.enabled", null); - for (Iterator i = stagedEnabled.iterator(); i.hasNext();) { - String nextName = i.next(); - Class next = null; - try { - next = Class.forName(getClass().getPackage().getName() + "." + nextName); - } catch (ClassNotFoundException e) {} - - if (next == null || !PermissionsResolver.class.isAssignableFrom(next)) { - logger.warning("WEPIF: Invalid or unknown class found in enabled resolvers: " - + nextName + ". Moving to disabled resolvers list."); - i.remove(); - disabledResolvers.add(nextName); - isUpdated = true; - continue; - } - enabledResolvers.add(next.asSubclass(PermissionsResolver.class)); - } - - for (Class clazz : availableResolvers) { - if (!stagedEnabled.contains(clazz.getSimpleName()) && - !disabledResolvers.contains(clazz.getSimpleName())) { - disabledResolvers.add(clazz.getSimpleName()); - logger.info("New permissions resolver: " - + clazz.getSimpleName() + " detected. " + - "Added to disabled resolvers list."); - isUpdated = true; - } - } - config.setProperty("resolvers.disabled", disabledResolvers); - config.setProperty("resolvers.enabled", stagedEnabled); - } - - if (keys.contains("dinner-perms") || keys.contains("dinnerperms")) { - config.removeProperty("dinner-perms"); - config.removeProperty("dinnerperms"); - isUpdated = true; - } - if (!keys.contains("permissions")) { - ConfigurationPermissionsResolver.generateDefaultPerms( - config.addNode("permissions")); - isUpdated = true; - } - if (isUpdated) { - logger.info("WEPIF: Updated config file"); - config.save(); - } - return isUpdated; - } - - public static class MissingPluginException extends Exception { - private static final long serialVersionUID = 7044832912491608706L; - } - - class ServerListener implements org.bukkit.event.Listener { - @EventHandler - public void onPluginEnable(PluginEnableEvent event) { - Plugin plugin = event.getPlugin(); - String name = plugin.getDescription().getName(); - if (plugin instanceof PermissionsProvider) { - setPluginPermissionsResolver(plugin); - } else if ("permissions".equalsIgnoreCase(name) || "permissionsex".equalsIgnoreCase(name) - || "bpermissions".equalsIgnoreCase(name) || "groupmanager".equalsIgnoreCase(name)) { - load(); - } - } - - @EventHandler - public void onPluginDisable(PluginDisableEvent event) { - String name = event.getPlugin().getDescription().getName(); - - if (event.getPlugin() instanceof PermissionsProvider - || "permissions".equalsIgnoreCase(name) || "permissionsex".equalsIgnoreCase(name) - || "bpermissions".equalsIgnoreCase(name) || "groupmanager".equalsIgnoreCase(name)) { - load(); - } - } - - void register(Plugin plugin) { - plugin.getServer().getPluginManager().registerEvents(this, plugin); - } - } - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.wepif; + +import com.sk89q.util.yaml.YAMLFormat; +import com.sk89q.util.yaml.YAMLProcessor; +import org.bukkit.OfflinePlayer; +import org.bukkit.Server; +import org.bukkit.event.EventHandler; +import org.bukkit.event.server.PluginDisableEvent; +import org.bukkit.event.server.PluginEnableEvent; +import org.bukkit.plugin.Plugin; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.logging.Logger; + +public class PermissionsResolverManager implements PermissionsResolver { + private static final String CONFIG_HEADER = "#\r\n" + + "# WEPIF Configuration File\r\n" + + "#\r\n" + + "# This file handles permissions configuration for every plugin using WEPIF\r\n" + + "#\r\n" + + "# About editing this file:\r\n" + + "# - DO NOT USE TABS. You MUST use spaces or Bukkit will complain. If\r\n" + + "# you use an editor like Notepad++ (recommended for Windows users), you\r\n" + + "# must configure it to \"replace tabs with spaces.\" In Notepad++, this can\r\n" + + "# be changed in Settings > Preferences > Language Menu.\r\n" + + "# - Don't get rid of the indents. They are indented so some entries are\r\n" + + "# in categories (like \"enforce-single-session\" is in the \"protection\"\r\n" + + "# category.\r\n" + + "# - If you want to check the format of this file before putting it\r\n" + + "# into WEPIF, paste it into http://yaml-online-parser.appspot.com/\r\n" + + "# and see if it gives \"ERROR:\".\r\n" + + "# - Lines starting with # are comments and so they are ignored.\r\n" + + "#\r\n" + + "# About Configuration Permissions\r\n" + + "# - See http://wiki.sk89q.com/wiki/WorldEdit/Permissions/Bukkit\r\n" + + "# - Now with multiworld support (see example)\r\n" + + "\r\n"; + + private static PermissionsResolverManager instance; + + public static void initialize(Plugin plugin) { + if (!isInitialized()) { + instance = new PermissionsResolverManager(plugin); + } + } + + public static boolean isInitialized() { + return instance != null; + } + + public static PermissionsResolverManager getInstance() { + if (!isInitialized()) { + throw new WEPIFRuntimeException("WEPIF has not yet been initialized!"); + } + return instance; + } + + private Server server; + private PermissionsResolver permissionResolver; + private YAMLProcessor config; + private Logger logger = Logger.getLogger(getClass().getCanonicalName()); + private List> enabledResolvers = new ArrayList>(); + + @SuppressWarnings("unchecked") + protected Class[] availableResolvers = new Class[] { + PluginPermissionsResolver.class, + PermissionsExResolver.class, + bPermissionsResolver.class, + GroupManagerResolver.class, + NijiPermissionsResolver.class, + DinnerPermsResolver.class, + FlatFilePermissionsResolver.class + }; + + protected PermissionsResolverManager(Plugin plugin) { + this.server = plugin.getServer(); + (new ServerListener()).register(plugin); // Register the events + + loadConfig(new File("wepif.yml")); + findResolver(); + } + + public void findResolver() { + for (Class resolverClass : enabledResolvers) { + try { + Method factoryMethod = resolverClass.getMethod("factory", Server.class, YAMLProcessor.class); + + this.permissionResolver = (PermissionsResolver) factoryMethod.invoke(null, this.server, this.config); + + if (this.permissionResolver != null) { + break; + } + } catch (Throwable e) { + logger.warning("Error in factory method for " + resolverClass.getSimpleName() + ": " + e); + e.printStackTrace(); + continue; + } + } + if (permissionResolver == null) { + permissionResolver = new ConfigurationPermissionsResolver(config); + } + permissionResolver.load(); + logger.info("WEPIF: " + permissionResolver.getDetectionMessage()); + } + + public void setPluginPermissionsResolver(Plugin plugin) { + if (!(plugin instanceof PermissionsProvider)) { + return; + } + + permissionResolver = new PluginPermissionsResolver((PermissionsProvider) plugin, plugin); + logger.info("WEPIF: " + permissionResolver.getDetectionMessage()); + } + + public void load() { + findResolver(); + } + + public boolean hasPermission(String name, String permission) { + return permissionResolver.hasPermission(name, permission); + } + + public boolean hasPermission(String worldName, String name, String permission) { + return permissionResolver.hasPermission(worldName, name, permission); + } + + public boolean inGroup(String player, String group) { + return permissionResolver.inGroup(player, group); + } + + public String[] getGroups(String player) { + return permissionResolver.getGroups(player); + } + + public boolean hasPermission(OfflinePlayer player, String permission) { + return permissionResolver.hasPermission(player, permission); + } + + public boolean hasPermission(String worldName, OfflinePlayer player, String permission) { + return permissionResolver.hasPermission(worldName, player, permission); + } + + public boolean inGroup(OfflinePlayer player, String group) { + return permissionResolver.inGroup(player, group); + } + + public String[] getGroups(OfflinePlayer player) { + return permissionResolver.getGroups(player); + } + + public String getDetectionMessage() { + return "Using WEPIF for permissions"; + } + + private boolean loadConfig(File file) { + boolean isUpdated = false; + if (!file.exists()) { + try { + file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + } + config = new YAMLProcessor(file, false, YAMLFormat.EXTENDED); + try { + config.load(); + } catch (IOException e) { + logger.severe("Error loading WEPIF Config: " + e); + e.printStackTrace(); + } + List keys = config.getKeys(null); + config.setHeader(CONFIG_HEADER); + + if (!keys.contains("ignore-nijiperms-bridges")) { + config.setProperty("ignore-nijiperms-bridges", true); + isUpdated = true; + } + + if (!keys.contains("resolvers")) { + //List resolverKeys = config.getKeys("resolvers"); + List resolvers = new ArrayList(); + for (Class clazz : availableResolvers) { + resolvers.add(clazz.getSimpleName()); + } + enabledResolvers.addAll(Arrays.asList(availableResolvers)); + config.setProperty("resolvers.enabled", resolvers); + isUpdated = true; + } else { + List disabledResolvers = config.getStringList("resolvers.disabled", new ArrayList()); + List stagedEnabled = config.getStringList("resolvers.enabled", null); + for (Iterator i = stagedEnabled.iterator(); i.hasNext();) { + String nextName = i.next(); + Class next = null; + try { + next = Class.forName(getClass().getPackage().getName() + "." + nextName); + } catch (ClassNotFoundException e) {} + + if (next == null || !PermissionsResolver.class.isAssignableFrom(next)) { + logger.warning("WEPIF: Invalid or unknown class found in enabled resolvers: " + + nextName + ". Moving to disabled resolvers list."); + i.remove(); + disabledResolvers.add(nextName); + isUpdated = true; + continue; + } + enabledResolvers.add(next.asSubclass(PermissionsResolver.class)); + } + + for (Class clazz : availableResolvers) { + if (!stagedEnabled.contains(clazz.getSimpleName()) && + !disabledResolvers.contains(clazz.getSimpleName())) { + disabledResolvers.add(clazz.getSimpleName()); + logger.info("New permissions resolver: " + + clazz.getSimpleName() + " detected. " + + "Added to disabled resolvers list."); + isUpdated = true; + } + } + config.setProperty("resolvers.disabled", disabledResolvers); + config.setProperty("resolvers.enabled", stagedEnabled); + } + + if (keys.contains("dinner-perms") || keys.contains("dinnerperms")) { + config.removeProperty("dinner-perms"); + config.removeProperty("dinnerperms"); + isUpdated = true; + } + if (!keys.contains("permissions")) { + ConfigurationPermissionsResolver.generateDefaultPerms( + config.addNode("permissions")); + isUpdated = true; + } + if (isUpdated) { + logger.info("WEPIF: Updated config file"); + config.save(); + } + return isUpdated; + } + + public static class MissingPluginException extends Exception { + private static final long serialVersionUID = 7044832912491608706L; + } + + class ServerListener implements org.bukkit.event.Listener { + @EventHandler + public void onPluginEnable(PluginEnableEvent event) { + Plugin plugin = event.getPlugin(); + String name = plugin.getDescription().getName(); + if (plugin instanceof PermissionsProvider) { + setPluginPermissionsResolver(plugin); + } else if ("permissions".equalsIgnoreCase(name) || "permissionsex".equalsIgnoreCase(name) + || "bpermissions".equalsIgnoreCase(name) || "groupmanager".equalsIgnoreCase(name)) { + load(); + } + } + + @EventHandler + public void onPluginDisable(PluginDisableEvent event) { + String name = event.getPlugin().getDescription().getName(); + + if (event.getPlugin() instanceof PermissionsProvider + || "permissions".equalsIgnoreCase(name) || "permissionsex".equalsIgnoreCase(name) + || "bpermissions".equalsIgnoreCase(name) || "groupmanager".equalsIgnoreCase(name)) { + load(); + } + } + + void register(Plugin plugin) { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + } + +} diff --git a/src/main/java/com/sk89q/wepif/PluginPermissionsResolver.java b/src/bukkit/java/com/sk89q/wepif/PluginPermissionsResolver.java similarity index 97% rename from src/main/java/com/sk89q/wepif/PluginPermissionsResolver.java rename to src/bukkit/java/com/sk89q/wepif/PluginPermissionsResolver.java index 18e790b7b..2f3541380 100644 --- a/src/main/java/com/sk89q/wepif/PluginPermissionsResolver.java +++ b/src/bukkit/java/com/sk89q/wepif/PluginPermissionsResolver.java @@ -1,95 +1,95 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.wepif; - -import com.sk89q.util.yaml.YAMLProcessor; -import org.bukkit.OfflinePlayer; -import org.bukkit.Server; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.RegisteredServiceProvider; - -public class PluginPermissionsResolver implements PermissionsResolver { - - protected PermissionsProvider resolver; - protected Plugin plugin; - - public static PermissionsResolver factory(Server server, YAMLProcessor config) { - // Looking for service - RegisteredServiceProvider serviceProvider = server.getServicesManager().getRegistration(PermissionsProvider.class); - - if (serviceProvider != null) { - return new PluginPermissionsResolver(serviceProvider.getProvider(), serviceProvider.getPlugin()); - } - - // Looking for plugin - for (Plugin plugin : server.getPluginManager().getPlugins()) { - if (plugin instanceof PermissionsProvider) { - return new PluginPermissionsResolver((PermissionsProvider) plugin, plugin); - } - } - - return null; - } - - public PluginPermissionsResolver(PermissionsProvider resolver, Plugin permissionsPlugin) { - this.resolver = resolver; - this.plugin = permissionsPlugin; - } - - public void load() { - } - - public boolean hasPermission(String name, String permission) { - return resolver.hasPermission(name, permission); - } - - public boolean hasPermission(String worldName, String name, String permission) { - return resolver.hasPermission(worldName, name, permission); - } - - public boolean inGroup(String player, String group) { - return resolver.inGroup(player, group); - } - - public String[] getGroups(String player) { - return resolver.getGroups(player); - } - - public boolean hasPermission(OfflinePlayer player, String permission) { - return resolver.hasPermission(player, permission); - } - - public boolean hasPermission(String worldName, OfflinePlayer player, String permission) { - return resolver.hasPermission(worldName, player, permission); - } - - public boolean inGroup(OfflinePlayer player, String group) { - return resolver.inGroup(player, group); - } - - public String[] getGroups(OfflinePlayer player) { - return resolver.getGroups(player); - } - - public String getDetectionMessage() { - return "Using plugin '" + this.plugin.getDescription().getName() + "' for permissions."; - } - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.wepif; + +import com.sk89q.util.yaml.YAMLProcessor; +import org.bukkit.OfflinePlayer; +import org.bukkit.Server; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.RegisteredServiceProvider; + +public class PluginPermissionsResolver implements PermissionsResolver { + + protected PermissionsProvider resolver; + protected Plugin plugin; + + public static PermissionsResolver factory(Server server, YAMLProcessor config) { + // Looking for service + RegisteredServiceProvider serviceProvider = server.getServicesManager().getRegistration(PermissionsProvider.class); + + if (serviceProvider != null) { + return new PluginPermissionsResolver(serviceProvider.getProvider(), serviceProvider.getPlugin()); + } + + // Looking for plugin + for (Plugin plugin : server.getPluginManager().getPlugins()) { + if (plugin instanceof PermissionsProvider) { + return new PluginPermissionsResolver((PermissionsProvider) plugin, plugin); + } + } + + return null; + } + + public PluginPermissionsResolver(PermissionsProvider resolver, Plugin permissionsPlugin) { + this.resolver = resolver; + this.plugin = permissionsPlugin; + } + + public void load() { + } + + public boolean hasPermission(String name, String permission) { + return resolver.hasPermission(name, permission); + } + + public boolean hasPermission(String worldName, String name, String permission) { + return resolver.hasPermission(worldName, name, permission); + } + + public boolean inGroup(String player, String group) { + return resolver.inGroup(player, group); + } + + public String[] getGroups(String player) { + return resolver.getGroups(player); + } + + public boolean hasPermission(OfflinePlayer player, String permission) { + return resolver.hasPermission(player, permission); + } + + public boolean hasPermission(String worldName, OfflinePlayer player, String permission) { + return resolver.hasPermission(worldName, player, permission); + } + + public boolean inGroup(OfflinePlayer player, String group) { + return resolver.inGroup(player, group); + } + + public String[] getGroups(OfflinePlayer player) { + return resolver.getGroups(player); + } + + public String getDetectionMessage() { + return "Using plugin '" + this.plugin.getDescription().getName() + "' for permissions."; + } + +} diff --git a/src/main/java/com/sk89q/wepif/WEPIFRuntimeException.java b/src/bukkit/java/com/sk89q/wepif/WEPIFRuntimeException.java similarity index 97% rename from src/main/java/com/sk89q/wepif/WEPIFRuntimeException.java rename to src/bukkit/java/com/sk89q/wepif/WEPIFRuntimeException.java index e99f03875..04e381eac 100644 --- a/src/main/java/com/sk89q/wepif/WEPIFRuntimeException.java +++ b/src/bukkit/java/com/sk89q/wepif/WEPIFRuntimeException.java @@ -1,31 +1,31 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.wepif; - -/** - * @author zml2008 - */ -public class WEPIFRuntimeException extends RuntimeException { - private static final long serialVersionUID = 5092745960439109699L; - - public WEPIFRuntimeException(String message) { - super(message); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.wepif; + +/** + * @author zml2008 + */ +public class WEPIFRuntimeException extends RuntimeException { + private static final long serialVersionUID = 5092745960439109699L; + + public WEPIFRuntimeException(String message) { + super(message); + } +} diff --git a/src/main/java/com/sk89q/wepif/bPermissionsResolver.java b/src/bukkit/java/com/sk89q/wepif/bPermissionsResolver.java similarity index 100% rename from src/main/java/com/sk89q/wepif/bPermissionsResolver.java rename to src/bukkit/java/com/sk89q/wepif/bPermissionsResolver.java diff --git a/src/main/java/com/sk89q/worldedit/bukkit/BukkitBiomeType.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitBiomeType.java similarity index 100% rename from src/main/java/com/sk89q/worldedit/bukkit/BukkitBiomeType.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitBiomeType.java diff --git a/src/main/java/com/sk89q/worldedit/bukkit/BukkitBiomeTypes.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitBiomeTypes.java similarity index 100% rename from src/main/java/com/sk89q/worldedit/bukkit/BukkitBiomeTypes.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitBiomeTypes.java diff --git a/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java index 5747a4607..2b6728be4 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java @@ -1,134 +1,134 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.bukkit; - -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalWorld; -import com.sk89q.worldedit.PlayerNeededException; -import com.sk89q.worldedit.ServerInterface; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.WorldVector; -import com.sk89q.worldedit.bags.BlockBag; - -public class BukkitCommandSender extends LocalPlayer { - private CommandSender sender; - private WorldEditPlugin plugin; - - public BukkitCommandSender(WorldEditPlugin plugin, ServerInterface server, CommandSender sender) { - super(server); - this.plugin = plugin; - this.sender = sender; - } - - @Override - public String getName() { - return sender.getName(); - } - - @Override - public void printRaw(String msg) { - for (String part : msg.split("\n")) { - sender.sendMessage(part); - } - } - - @Override - public void print(String msg) { - for (String part : msg.split("\n")) { - sender.sendMessage("\u00A7d" + part); - } - } - - @Override - public void printDebug(String msg) { - for (String part : msg.split("\n")) { - sender.sendMessage("\u00A77" + part); - } - } - - @Override - public void printError(String msg) { - for (String part : msg.split("\n")) { - sender.sendMessage("\u00A7c" + part); - } - } - - @Override - public String[] getGroups() { - return new String[0]; - } - - @Override - public boolean hasPermission(String perm) { - if (!plugin.getLocalConfiguration().noOpPermissions && sender.isOp()) { - return true; - } - - return plugin.getPermissionsResolver().hasPermission(null, sender.getName(), perm); - } - - @Override - public boolean isPlayer() { - return sender instanceof Player; - } - - @Override - public int getItemInHand() { - throw new PlayerNeededException(); - } - - @Override - public WorldVector getPosition() { - throw new PlayerNeededException(); - } - - @Override - public LocalWorld getWorld() { - throw new PlayerNeededException(); - } - - @Override - public double getPitch() { - throw new PlayerNeededException(); - } - - @Override - public double getYaw() { - throw new PlayerNeededException(); - } - - @Override - public void giveItem(int type, int amt) { - throw new PlayerNeededException(); - } - - @Override - public void setPosition(Vector pos, float pitch, float yaw) { - throw new PlayerNeededException(); - } - - @Override - public BlockBag getInventoryBlockBag() { - throw new PlayerNeededException(); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.bukkit; + +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.PlayerNeededException; +import com.sk89q.worldedit.ServerInterface; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldVector; +import com.sk89q.worldedit.extent.inventory.BlockBag; + +public class BukkitCommandSender extends LocalPlayer { + private CommandSender sender; + private WorldEditPlugin plugin; + + public BukkitCommandSender(WorldEditPlugin plugin, ServerInterface server, CommandSender sender) { + super(server); + this.plugin = plugin; + this.sender = sender; + } + + @Override + public String getName() { + return sender.getName(); + } + + @Override + public void printRaw(String msg) { + for (String part : msg.split("\n")) { + sender.sendMessage(part); + } + } + + @Override + public void print(String msg) { + for (String part : msg.split("\n")) { + sender.sendMessage("\u00A7d" + part); + } + } + + @Override + public void printDebug(String msg) { + for (String part : msg.split("\n")) { + sender.sendMessage("\u00A77" + part); + } + } + + @Override + public void printError(String msg) { + for (String part : msg.split("\n")) { + sender.sendMessage("\u00A7c" + part); + } + } + + @Override + public String[] getGroups() { + return new String[0]; + } + + @Override + public boolean hasPermission(String perm) { + if (!plugin.getLocalConfiguration().noOpPermissions && sender.isOp()) { + return true; + } + + return plugin.getPermissionsResolver().hasPermission(null, sender.getName(), perm); + } + + @Override + public boolean isPlayer() { + return sender instanceof Player; + } + + @Override + public int getItemInHand() { + throw new PlayerNeededException(); + } + + @Override + public WorldVector getPosition() { + throw new PlayerNeededException(); + } + + @Override + public LocalWorld getWorld() { + throw new PlayerNeededException(); + } + + @Override + public double getPitch() { + throw new PlayerNeededException(); + } + + @Override + public double getYaw() { + throw new PlayerNeededException(); + } + + @Override + public void giveItem(int type, int amt) { + throw new PlayerNeededException(); + } + + @Override + public void setPosition(Vector pos, float pitch, float yaw) { + throw new PlayerNeededException(); + } + + @Override + public BlockBag getInventoryBlockBag() { + throw new PlayerNeededException(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/bukkit/BukkitConfiguration.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitConfiguration.java similarity index 100% rename from src/main/java/com/sk89q/worldedit/bukkit/BukkitConfiguration.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitConfiguration.java diff --git a/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java index 7374105e7..8cb16e8b1 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java @@ -1,171 +1,171 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.bukkit; - -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.blocks.BaseBlock; -import org.bukkit.GameMode; -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; - -import com.sk89q.util.StringUtil; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalWorld; -import com.sk89q.worldedit.ServerInterface; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.WorldVector; -import com.sk89q.worldedit.bags.BlockBag; -import com.sk89q.worldedit.cui.CUIEvent; - -public class BukkitPlayer extends LocalPlayer { - private Player player; - private WorldEditPlugin plugin; - - public BukkitPlayer(WorldEditPlugin plugin, ServerInterface server, Player player) { - super(server); - this.plugin = plugin; - this.player = player; - } - - @Override - public int getItemInHand() { - ItemStack itemStack = player.getItemInHand(); - return itemStack != null ? itemStack.getTypeId() : 0; - } - - public BaseBlock getBlockInHand() throws WorldEditException { - ItemStack itemStack = player.getItemInHand(); - return BukkitUtil.toBlock(getWorld(), itemStack); - } - - @Override - public String getName() { - return player.getName(); - } - - @Override - public WorldVector getPosition() { - Location loc = player.getLocation(); - return new WorldVector(BukkitUtil.getLocalWorld(loc.getWorld()), - loc.getX(), loc.getY(), loc.getZ()); - } - - @Override - public double getPitch() { - return player.getLocation().getPitch(); - } - - @Override - public double getYaw() { - return player.getLocation().getYaw(); - } - - @Override - public void giveItem(int type, int amt) { - player.getInventory().addItem(new ItemStack(type, amt)); - } - - @Override - public void printRaw(String msg) { - for (String part : msg.split("\n")) { - player.sendMessage(part); - } - } - - @Override - public void print(String msg) { - for (String part : msg.split("\n")) { - player.sendMessage("\u00A7d" + part); - } - } - - @Override - public void printDebug(String msg) { - for (String part : msg.split("\n")) { - player.sendMessage("\u00A77" + part); - } - } - - @Override - public void printError(String msg) { - for (String part : msg.split("\n")) { - player.sendMessage("\u00A7c" + part); - } - } - - @Override - public void setPosition(Vector pos, float pitch, float yaw) { - player.teleport(new Location(player.getWorld(), pos.getX(), pos.getY(), - pos.getZ(), yaw, pitch)); - } - - @Override - public String[] getGroups() { - return plugin.getPermissionsResolver().getGroups(player); - } - - @Override - public BlockBag getInventoryBlockBag() { - return new BukkitPlayerBlockBag(player); - } - - @Override - public boolean hasPermission(String perm) { - return (!plugin.getLocalConfiguration().noOpPermissions && player.isOp()) - || plugin.getPermissionsResolver().hasPermission( - player.getWorld().getName(), player, perm); - } - - @Override - public LocalWorld getWorld() { - return BukkitUtil.getLocalWorld(player.getWorld()); - } - - @Override - public void dispatchCUIEvent(CUIEvent event) { - String[] params = event.getParameters(); - String send = event.getTypeId(); - if (params.length > 0) { - send = send + "|" + StringUtil.joinString(params, "|"); - } - player.sendPluginMessage(plugin, WorldEditPlugin.CUI_PLUGIN_CHANNEL, send.getBytes(CUIChannelListener.UTF_8_CHARSET)); - } - - public Player getPlayer() { - return player; - } - - @Override - public boolean hasCreativeMode() { - return player.getGameMode() == GameMode.CREATIVE; - } - - @Override - public void floatAt(int x, int y, int z, boolean alwaysGlass) { - if (alwaysGlass || !player.getAllowFlight()) { - super.floatAt(x, y, z, alwaysGlass); - return; - } - - setPosition(new Vector(x + 0.5, y, z + 0.5)); - player.setFlying(true); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.bukkit; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import com.sk89q.util.StringUtil; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.ServerInterface; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldVector; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.internal.cui.CUIEvent; + +public class BukkitPlayer extends LocalPlayer { + private Player player; + private WorldEditPlugin plugin; + + public BukkitPlayer(WorldEditPlugin plugin, ServerInterface server, Player player) { + super(server); + this.plugin = plugin; + this.player = player; + } + + @Override + public int getItemInHand() { + ItemStack itemStack = player.getItemInHand(); + return itemStack != null ? itemStack.getTypeId() : 0; + } + + public BaseBlock getBlockInHand() throws WorldEditException { + ItemStack itemStack = player.getItemInHand(); + return BukkitUtil.toBlock(getWorld(), itemStack); + } + + @Override + public String getName() { + return player.getName(); + } + + @Override + public WorldVector getPosition() { + Location loc = player.getLocation(); + return new WorldVector(BukkitUtil.getLocalWorld(loc.getWorld()), + loc.getX(), loc.getY(), loc.getZ()); + } + + @Override + public double getPitch() { + return player.getLocation().getPitch(); + } + + @Override + public double getYaw() { + return player.getLocation().getYaw(); + } + + @Override + public void giveItem(int type, int amt) { + player.getInventory().addItem(new ItemStack(type, amt)); + } + + @Override + public void printRaw(String msg) { + for (String part : msg.split("\n")) { + player.sendMessage(part); + } + } + + @Override + public void print(String msg) { + for (String part : msg.split("\n")) { + player.sendMessage("\u00A7d" + part); + } + } + + @Override + public void printDebug(String msg) { + for (String part : msg.split("\n")) { + player.sendMessage("\u00A77" + part); + } + } + + @Override + public void printError(String msg) { + for (String part : msg.split("\n")) { + player.sendMessage("\u00A7c" + part); + } + } + + @Override + public void setPosition(Vector pos, float pitch, float yaw) { + player.teleport(new Location(player.getWorld(), pos.getX(), pos.getY(), + pos.getZ(), yaw, pitch)); + } + + @Override + public String[] getGroups() { + return plugin.getPermissionsResolver().getGroups(player); + } + + @Override + public BlockBag getInventoryBlockBag() { + return new BukkitPlayerBlockBag(player); + } + + @Override + public boolean hasPermission(String perm) { + return (!plugin.getLocalConfiguration().noOpPermissions && player.isOp()) + || plugin.getPermissionsResolver().hasPermission( + player.getWorld().getName(), player, perm); + } + + @Override + public LocalWorld getWorld() { + return BukkitUtil.getLocalWorld(player.getWorld()); + } + + @Override + public void dispatchCUIEvent(CUIEvent event) { + String[] params = event.getParameters(); + String send = event.getTypeId(); + if (params.length > 0) { + send = send + "|" + StringUtil.joinString(params, "|"); + } + player.sendPluginMessage(plugin, WorldEditPlugin.CUI_PLUGIN_CHANNEL, send.getBytes(CUIChannelListener.UTF_8_CHARSET)); + } + + public Player getPlayer() { + return player; + } + + @Override + public boolean hasCreativeMode() { + return player.getGameMode() == GameMode.CREATIVE; + } + + @Override + public void floatAt(int x, int y, int z, boolean alwaysGlass) { + if (alwaysGlass || !player.getAllowFlight()) { + super.floatAt(x, y, z, alwaysGlass); + return; + } + + setPosition(new Vector(x + 0.5, y, z + 0.5)); + player.setFlying(true); + } +} diff --git a/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayerBlockBag.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayerBlockBag.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayerBlockBag.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayerBlockBag.java index ab66726b3..b2807d223 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayerBlockBag.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayerBlockBag.java @@ -1,228 +1,228 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.bukkit; - -import com.sk89q.worldedit.WorldVector; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import com.sk89q.worldedit.bags.*; -import com.sk89q.worldedit.blocks.BaseItem; -import com.sk89q.worldedit.blocks.BaseItemStack; -import com.sk89q.worldedit.blocks.BlockID; -import com.sk89q.worldedit.blocks.ItemType; - -public class BukkitPlayerBlockBag extends BlockBag { - /** - * Player instance. - */ - private Player player; - /** - * The player's inventory; - */ - private ItemStack[] items; - - /** - * Construct the object. - * - * @param player - */ - public BukkitPlayerBlockBag(Player player) { - this.player = player; - } - - /** - * Loads inventory on first use. - */ - private void loadInventory() { - if (items == null) { - items = player.getInventory().getContents(); - } - } - - /** - * Get the player. - * - * @return - */ - public Player getPlayer() { - return player; - } - - /** - * Get a block. - * - * @param id - */ - @Override - public void fetchItem(BaseItem item) throws BlockBagException { - final int id = item.getType(); - final int damage = item.getData(); - int amount = (item instanceof BaseItemStack) ? ((BaseItemStack) item).getAmount() : 1; - assert(amount == 1); - boolean usesDamageValue = ItemType.usesDamageValue(id); - - if (id == BlockID.AIR) { - throw new IllegalArgumentException("Can't fetch air block"); - } - - loadInventory(); - - boolean found = false; - - for (int slot = 0; slot < items.length; ++slot) { - ItemStack bukkitItem = items[slot]; - - if (bukkitItem == null) { - continue; - } - - if (bukkitItem.getTypeId() != id) { - // Type id doesn't fit - continue; - } - - if (usesDamageValue && bukkitItem.getDurability() != damage) { - // Damage value doesn't fit. - continue; - } - - int currentAmount = bukkitItem.getAmount(); - if (currentAmount < 0) { - // Unlimited - return; - } - - if (currentAmount > 1) { - bukkitItem.setAmount(currentAmount - 1); - found = true; - } else { - items[slot] = null; - found = true; - } - - break; - } - - if (!found) { - throw new OutOfBlocksException(); - } - } - - /** - * Store a block. - * - * @param id - */ - @Override - public void storeItem(BaseItem item) throws BlockBagException { - final int id = item.getType(); - final int damage = item.getData(); - int amount = (item instanceof BaseItemStack) ? ((BaseItemStack) item).getAmount() : 1; - assert(amount <= 64); - boolean usesDamageValue = ItemType.usesDamageValue(id); - - if (id == BlockID.AIR) { - throw new IllegalArgumentException("Can't store air block"); - } - - loadInventory(); - - int freeSlot = -1; - - for (int slot = 0; slot < items.length; ++slot) { - ItemStack bukkitItem = items[slot]; - - if (bukkitItem == null) { - // Delay using up a free slot until we know there are no stacks - // of this item to merge into - - if (freeSlot == -1) { - freeSlot = slot; - } - continue; - } - - if (bukkitItem.getTypeId() != id) { - // Type id doesn't fit - continue; - } - - if (usesDamageValue && bukkitItem.getDurability() != damage) { - // Damage value doesn't fit. - continue; - } - - int currentAmount = bukkitItem.getAmount(); - if (currentAmount < 0) { - // Unlimited - return; - } - if (currentAmount >= 64) { - // Full stack - continue; - } - - int spaceLeft = 64 - currentAmount; - if (spaceLeft >= amount) { - bukkitItem.setAmount(currentAmount + amount); - return; - } - - bukkitItem.setAmount(64); - amount -= spaceLeft; - } - - if (freeSlot > -1) { - items[freeSlot] = new ItemStack(id, amount); - return; - } - - throw new OutOfSpaceException(id); - } - - /** - * Flush any changes. This is called at the end. - */ - @Override - public void flushChanges() { - if (items != null) { - player.getInventory().setContents(items); - items = null; - } - } - - /** - * Adds a position to be used a source. - * - * @param pos - */ - @Override - public void addSourcePosition(WorldVector pos) { - } - - /** - * Adds a position to be used a source. - * - * @param pos - */ - @Override - public void addSingleSourcePosition(WorldVector pos) { - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.bukkit; + +import com.sk89q.worldedit.WorldVector; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import com.sk89q.worldedit.extent.inventory.*; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.blocks.BlockID; +import com.sk89q.worldedit.blocks.ItemType; + +public class BukkitPlayerBlockBag extends BlockBag { + /** + * Player instance. + */ + private Player player; + /** + * The player's inventory; + */ + private ItemStack[] items; + + /** + * Construct the object. + * + * @param player + */ + public BukkitPlayerBlockBag(Player player) { + this.player = player; + } + + /** + * Loads inventory on first use. + */ + private void loadInventory() { + if (items == null) { + items = player.getInventory().getContents(); + } + } + + /** + * Get the player. + * + * @return + */ + public Player getPlayer() { + return player; + } + + /** + * Get a block. + * + * @param id + */ + @Override + public void fetchItem(BaseItem item) throws BlockBagException { + final int id = item.getType(); + final int damage = item.getData(); + int amount = (item instanceof BaseItemStack) ? ((BaseItemStack) item).getAmount() : 1; + assert(amount == 1); + boolean usesDamageValue = ItemType.usesDamageValue(id); + + if (id == BlockID.AIR) { + throw new IllegalArgumentException("Can't fetch air block"); + } + + loadInventory(); + + boolean found = false; + + for (int slot = 0; slot < items.length; ++slot) { + ItemStack bukkitItem = items[slot]; + + if (bukkitItem == null) { + continue; + } + + if (bukkitItem.getTypeId() != id) { + // Type id doesn't fit + continue; + } + + if (usesDamageValue && bukkitItem.getDurability() != damage) { + // Damage value doesn't fit. + continue; + } + + int currentAmount = bukkitItem.getAmount(); + if (currentAmount < 0) { + // Unlimited + return; + } + + if (currentAmount > 1) { + bukkitItem.setAmount(currentAmount - 1); + found = true; + } else { + items[slot] = null; + found = true; + } + + break; + } + + if (!found) { + throw new OutOfBlocksException(); + } + } + + /** + * Store a block. + * + * @param id + */ + @Override + public void storeItem(BaseItem item) throws BlockBagException { + final int id = item.getType(); + final int damage = item.getData(); + int amount = (item instanceof BaseItemStack) ? ((BaseItemStack) item).getAmount() : 1; + assert(amount <= 64); + boolean usesDamageValue = ItemType.usesDamageValue(id); + + if (id == BlockID.AIR) { + throw new IllegalArgumentException("Can't store air block"); + } + + loadInventory(); + + int freeSlot = -1; + + for (int slot = 0; slot < items.length; ++slot) { + ItemStack bukkitItem = items[slot]; + + if (bukkitItem == null) { + // Delay using up a free slot until we know there are no stacks + // of this item to merge into + + if (freeSlot == -1) { + freeSlot = slot; + } + continue; + } + + if (bukkitItem.getTypeId() != id) { + // Type id doesn't fit + continue; + } + + if (usesDamageValue && bukkitItem.getDurability() != damage) { + // Damage value doesn't fit. + continue; + } + + int currentAmount = bukkitItem.getAmount(); + if (currentAmount < 0) { + // Unlimited + return; + } + if (currentAmount >= 64) { + // Full stack + continue; + } + + int spaceLeft = 64 - currentAmount; + if (spaceLeft >= amount) { + bukkitItem.setAmount(currentAmount + amount); + return; + } + + bukkitItem.setAmount(64); + amount -= spaceLeft; + } + + if (freeSlot > -1) { + items[freeSlot] = new ItemStack(id, amount); + return; + } + + throw new OutOfSpaceException(id); + } + + /** + * Flush any changes. This is called at the end. + */ + @Override + public void flushChanges() { + if (items != null) { + player.getInventory().setContents(items); + items = null; + } + } + + /** + * Adds a position to be used a source. + * + * @param pos + */ + @Override + public void addSourcePosition(WorldVector pos) { + } + + /** + * Adds a position to be used a source. + * + * @param pos + */ + @Override + public void addSingleSourcePosition(WorldVector pos) { + } +} diff --git a/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java similarity index 97% rename from src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java index 03d931ea6..642f30c62 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java @@ -1,125 +1,125 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.bukkit; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -import com.sk89q.bukkit.util.CommandInfo; -import com.sk89q.bukkit.util.CommandRegistration; -import com.sk89q.minecraft.util.commands.Command; - -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.CommandsManager; -import com.sk89q.worldedit.LocalPlayer; -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.Server; -import org.bukkit.World; -import org.bukkit.entity.EntityType; - -import com.sk89q.worldedit.BiomeTypes; -import com.sk89q.worldedit.LocalWorld; -import com.sk89q.worldedit.ServerInterface; - -public class BukkitServerInterface extends ServerInterface { - public Server server; - public WorldEditPlugin plugin; - private CommandRegistration dynamicCommands; - private BukkitBiomeTypes biomes; - - public BukkitServerInterface(WorldEditPlugin plugin, Server server) { - this.plugin = plugin; - this.server = server; - this.biomes = new BukkitBiomeTypes(); - dynamicCommands = new CommandRegistration(plugin); - } - - @Override - public int resolveItem(String name) { - Material mat = Material.matchMaterial(name); - return mat == null ? 0 : mat.getId(); - } - - @Override - public boolean isValidMobType(String type) { - final EntityType entityType = EntityType.fromName(type); - return entityType != null && entityType.isAlive(); - } - - @Override - public void reload() { - plugin.loadConfiguration(); - } - - @Override - public BiomeTypes getBiomes() { - return biomes; - } - - @Override - public int schedule(long delay, long period, Runnable task) { - return Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, task, delay, period); - } - - @Override - public List getWorlds() { - List worlds = server.getWorlds(); - List ret = new ArrayList(worlds.size()); - - for (World world : worlds) { - ret.add(BukkitUtil.getLocalWorld(world)); - } - - return ret; - } - - @Override - public void onCommandRegistration(List commands, CommandsManager manager) { - List toRegister = new ArrayList(); - for (Command command : commands) { - List permissions = null; - Method cmdMethod = manager.getMethods().get(null).get(command.aliases()[0]); - Map childMethods = manager.getMethods().get(cmdMethod); - - if (cmdMethod != null && cmdMethod.isAnnotationPresent(CommandPermissions.class)) { - permissions = Arrays.asList(cmdMethod.getAnnotation(CommandPermissions.class).value()); - } else if (cmdMethod != null && childMethods != null && childMethods.size() > 0) { - permissions = new ArrayList(); - for (Method m : childMethods.values()) { - if (m.isAnnotationPresent(CommandPermissions.class)) { - permissions.addAll(Arrays.asList(m.getAnnotation(CommandPermissions.class).value())); - } - } - } - - toRegister.add(new CommandInfo(command.usage(), command.desc(), command.aliases(), commands, permissions == null ? null : permissions.toArray(new String[permissions.size()]))); - } - - dynamicCommands.register(toRegister); - } - - public void unregisterCommands() { - dynamicCommands.unregisterCommands(); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.bukkit; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import com.sk89q.bukkit.util.CommandInfo; +import com.sk89q.bukkit.util.CommandRegistration; +import com.sk89q.minecraft.util.commands.Command; + +import com.sk89q.minecraft.util.commands.CommandPermissions; +import com.sk89q.minecraft.util.commands.CommandsManager; +import com.sk89q.worldedit.LocalPlayer; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.entity.EntityType; + +import com.sk89q.worldedit.BiomeTypes; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.ServerInterface; + +public class BukkitServerInterface extends ServerInterface { + public Server server; + public WorldEditPlugin plugin; + private CommandRegistration dynamicCommands; + private BukkitBiomeTypes biomes; + + public BukkitServerInterface(WorldEditPlugin plugin, Server server) { + this.plugin = plugin; + this.server = server; + this.biomes = new BukkitBiomeTypes(); + dynamicCommands = new CommandRegistration(plugin); + } + + @Override + public int resolveItem(String name) { + Material mat = Material.matchMaterial(name); + return mat == null ? 0 : mat.getId(); + } + + @Override + public boolean isValidMobType(String type) { + final EntityType entityType = EntityType.fromName(type); + return entityType != null && entityType.isAlive(); + } + + @Override + public void reload() { + plugin.loadConfiguration(); + } + + @Override + public BiomeTypes getBiomes() { + return biomes; + } + + @Override + public int schedule(long delay, long period, Runnable task) { + return Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, task, delay, period); + } + + @Override + public List getWorlds() { + List worlds = server.getWorlds(); + List ret = new ArrayList(worlds.size()); + + for (World world : worlds) { + ret.add(BukkitUtil.getLocalWorld(world)); + } + + return ret; + } + + @Override + public void onCommandRegistration(List commands, CommandsManager manager) { + List toRegister = new ArrayList(); + for (Command command : commands) { + List permissions = null; + Method cmdMethod = manager.getMethods().get(null).get(command.aliases()[0]); + Map childMethods = manager.getMethods().get(cmdMethod); + + if (cmdMethod != null && cmdMethod.isAnnotationPresent(CommandPermissions.class)) { + permissions = Arrays.asList(cmdMethod.getAnnotation(CommandPermissions.class).value()); + } else if (cmdMethod != null && childMethods != null && childMethods.size() > 0) { + permissions = new ArrayList(); + for (Method m : childMethods.values()) { + if (m.isAnnotationPresent(CommandPermissions.class)) { + permissions.addAll(Arrays.asList(m.getAnnotation(CommandPermissions.class).value())); + } + } + } + + toRegister.add(new CommandInfo(command.usage(), command.desc(), command.aliases(), commands, permissions == null ? null : permissions.toArray(new String[permissions.size()]))); + } + + dynamicCommands.register(toRegister); + } + + public void unregisterCommands() { + dynamicCommands.unregisterCommands(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/bukkit/BukkitUtil.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitUtil.java similarity index 97% rename from src/main/java/com/sk89q/worldedit/bukkit/BukkitUtil.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitUtil.java index c3c2c09ba..b4e3bcd23 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/BukkitUtil.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitUtil.java @@ -1,195 +1,195 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.bukkit; - -import java.util.List; - -import com.sk89q.worldedit.NotABlockException; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.blocks.BlockID; -import com.sk89q.worldedit.blocks.BlockType; -import com.sk89q.worldedit.blocks.ItemID; -import com.sk89q.worldedit.blocks.SkullBlock; -import org.bukkit.DyeColor; -import org.bukkit.Server; -import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.entity.Entity; -import org.bukkit.entity.ExperienceOrb; -import org.bukkit.entity.Item; -import org.bukkit.entity.Painting; -import org.bukkit.entity.Player; - -import com.sk89q.worldedit.BlockVector; -import com.sk89q.worldedit.BlockWorldVector; -import com.sk89q.worldedit.LocalWorld; -import com.sk89q.worldedit.Location; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.WorldVector; -import com.sk89q.worldedit.bukkit.entity.BukkitEntity; -import com.sk89q.worldedit.bukkit.entity.BukkitExpOrb; -import com.sk89q.worldedit.bukkit.entity.BukkitItem; -import com.sk89q.worldedit.bukkit.entity.BukkitPainting; -import org.bukkit.inventory.ItemStack; -import org.bukkit.material.Dye; - -public class BukkitUtil { - private BukkitUtil() { - } - - public static LocalWorld getLocalWorld(World w) { - return new BukkitWorld(w); - } - - public static BlockVector toVector(Block block) { - return new BlockVector(block.getX(), block.getY(), block.getZ()); - } - - public static BlockVector toVector(BlockFace face) { - return new BlockVector(face.getModX(), face.getModY(), face.getModZ()); - } - - public static BlockWorldVector toWorldVector(Block block) { - return new BlockWorldVector(getLocalWorld(block.getWorld()), block.getX(), block.getY(), block.getZ()); - } - - public static Vector toVector(org.bukkit.Location loc) { - return new Vector(loc.getX(), loc.getY(), loc.getZ()); - } - - public static Location toLocation(org.bukkit.Location loc) { - return new Location( - getLocalWorld(loc.getWorld()), - new Vector(loc.getX(), loc.getY(), loc.getZ()), - loc.getYaw(), loc.getPitch() - ); - } - - public static Vector toVector(org.bukkit.util.Vector vector) { - return new Vector(vector.getX(), vector.getY(), vector.getZ()); - } - - public static org.bukkit.Location toLocation(WorldVector pt) { - return new org.bukkit.Location(toWorld(pt), pt.getX(), pt.getY(), pt.getZ()); - } - - public static org.bukkit.Location toLocation(World world, Vector pt) { - return new org.bukkit.Location(world, pt.getX(), pt.getY(), pt.getZ()); - } - - public static org.bukkit.Location center(org.bukkit.Location loc) { - return new org.bukkit.Location( - loc.getWorld(), - loc.getBlockX() + 0.5, - loc.getBlockY() + 0.5, - loc.getBlockZ() + 0.5, - loc.getPitch(), - loc.getYaw() - ); - } - - public static Player matchSinglePlayer(Server server, String name) { - List players = server.matchPlayer(name); - if (players.size() == 0) { - return null; - } - return players.get(0); - } - - public static Block toBlock(BlockWorldVector pt) { - return toWorld(pt).getBlockAt(toLocation(pt)); - } - - public static World toWorld(WorldVector pt) { - return ((BukkitWorld) pt.getWorld()).getWorld(); - } - - /** - * Bukkit's Location class has serious problems with floating point - * precision. - */ - @SuppressWarnings("RedundantIfStatement") - public static boolean equals(org.bukkit.Location a, org.bukkit.Location b) { - if (Math.abs(a.getX() - b.getX()) > EQUALS_PRECISION) return false; - if (Math.abs(a.getY() - b.getY()) > EQUALS_PRECISION) return false; - if (Math.abs(a.getZ() - b.getZ()) > EQUALS_PRECISION) return false; - return true; - } - - public static final double EQUALS_PRECISION = 0.0001; - - public static org.bukkit.Location toLocation(Location location) { - Vector pt = location.getPosition(); - return new org.bukkit.Location( - toWorld(location.getWorld()), - pt.getX(), pt.getY(), pt.getZ(), - location.getYaw(), location.getPitch() - ); - } - - public static World toWorld(final LocalWorld world) { - return ((BukkitWorld) world).getWorld(); - } - - public static BukkitEntity toLocalEntity(Entity e) { - switch (e.getType()) { - case EXPERIENCE_ORB: - return new BukkitExpOrb(toLocation(e.getLocation()), e.getUniqueId(), ((ExperienceOrb)e).getExperience()); - case PAINTING: - Painting paint = (Painting) e; - return new BukkitPainting(toLocation(e.getLocation()), paint.getArt(), paint.getFacing(), e.getUniqueId()); - case DROPPED_ITEM: - return new BukkitItem(toLocation(e.getLocation()), ((Item)e).getItemStack(), e.getUniqueId()); - default: - return new BukkitEntity(toLocation(e.getLocation()), e.getType(), e.getUniqueId()); - } - } - - public static BaseBlock toBlock(LocalWorld world, ItemStack itemStack) throws WorldEditException { - final int typeId = itemStack.getTypeId(); - - switch (typeId) { - case ItemID.INK_SACK: - final Dye materialData = (Dye) itemStack.getData(); - if (materialData.getColor() == DyeColor.BROWN) { - return new BaseBlock(BlockID.COCOA_PLANT, -1); - } - break; - - case ItemID.HEAD: - return new SkullBlock(0, (byte) itemStack.getDurability()); - - default: - final BaseBlock baseBlock = BlockType.getBlockForItem(typeId, itemStack.getDurability()); - if (baseBlock != null) { - return baseBlock; - } - break; - } - - if (world.isValidBlockType(typeId)) { - return new BaseBlock(typeId, -1); - } - - throw new NotABlockException(typeId); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.bukkit; + +import java.util.List; + +import com.sk89q.worldedit.NotABlockException; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockID; +import com.sk89q.worldedit.blocks.BlockType; +import com.sk89q.worldedit.blocks.ItemID; +import com.sk89q.worldedit.blocks.SkullBlock; +import org.bukkit.DyeColor; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Entity; +import org.bukkit.entity.ExperienceOrb; +import org.bukkit.entity.Item; +import org.bukkit.entity.Painting; +import org.bukkit.entity.Player; + +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.BlockWorldVector; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.Location; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldVector; +import com.sk89q.worldedit.bukkit.entity.BukkitEntity; +import com.sk89q.worldedit.bukkit.entity.BukkitExpOrb; +import com.sk89q.worldedit.bukkit.entity.BukkitItem; +import com.sk89q.worldedit.bukkit.entity.BukkitPainting; +import org.bukkit.inventory.ItemStack; +import org.bukkit.material.Dye; + +public class BukkitUtil { + private BukkitUtil() { + } + + public static LocalWorld getLocalWorld(World w) { + return new BukkitWorld(w); + } + + public static BlockVector toVector(Block block) { + return new BlockVector(block.getX(), block.getY(), block.getZ()); + } + + public static BlockVector toVector(BlockFace face) { + return new BlockVector(face.getModX(), face.getModY(), face.getModZ()); + } + + public static BlockWorldVector toWorldVector(Block block) { + return new BlockWorldVector(getLocalWorld(block.getWorld()), block.getX(), block.getY(), block.getZ()); + } + + public static Vector toVector(org.bukkit.Location loc) { + return new Vector(loc.getX(), loc.getY(), loc.getZ()); + } + + public static Location toLocation(org.bukkit.Location loc) { + return new Location( + getLocalWorld(loc.getWorld()), + new Vector(loc.getX(), loc.getY(), loc.getZ()), + loc.getYaw(), loc.getPitch() + ); + } + + public static Vector toVector(org.bukkit.util.Vector vector) { + return new Vector(vector.getX(), vector.getY(), vector.getZ()); + } + + public static org.bukkit.Location toLocation(WorldVector pt) { + return new org.bukkit.Location(toWorld(pt), pt.getX(), pt.getY(), pt.getZ()); + } + + public static org.bukkit.Location toLocation(World world, Vector pt) { + return new org.bukkit.Location(world, pt.getX(), pt.getY(), pt.getZ()); + } + + public static org.bukkit.Location center(org.bukkit.Location loc) { + return new org.bukkit.Location( + loc.getWorld(), + loc.getBlockX() + 0.5, + loc.getBlockY() + 0.5, + loc.getBlockZ() + 0.5, + loc.getPitch(), + loc.getYaw() + ); + } + + public static Player matchSinglePlayer(Server server, String name) { + List players = server.matchPlayer(name); + if (players.size() == 0) { + return null; + } + return players.get(0); + } + + public static Block toBlock(BlockWorldVector pt) { + return toWorld(pt).getBlockAt(toLocation(pt)); + } + + public static World toWorld(WorldVector pt) { + return ((BukkitWorld) pt.getWorld()).getWorld(); + } + + /** + * Bukkit's Location class has serious problems with floating point + * precision. + */ + @SuppressWarnings("RedundantIfStatement") + public static boolean equals(org.bukkit.Location a, org.bukkit.Location b) { + if (Math.abs(a.getX() - b.getX()) > EQUALS_PRECISION) return false; + if (Math.abs(a.getY() - b.getY()) > EQUALS_PRECISION) return false; + if (Math.abs(a.getZ() - b.getZ()) > EQUALS_PRECISION) return false; + return true; + } + + public static final double EQUALS_PRECISION = 0.0001; + + public static org.bukkit.Location toLocation(Location location) { + Vector pt = location.getPosition(); + return new org.bukkit.Location( + toWorld(location.getWorld()), + pt.getX(), pt.getY(), pt.getZ(), + location.getYaw(), location.getPitch() + ); + } + + public static World toWorld(final LocalWorld world) { + return ((BukkitWorld) world).getWorld(); + } + + public static BukkitEntity toLocalEntity(Entity e) { + switch (e.getType()) { + case EXPERIENCE_ORB: + return new BukkitExpOrb(toLocation(e.getLocation()), e.getUniqueId(), ((ExperienceOrb)e).getExperience()); + case PAINTING: + Painting paint = (Painting) e; + return new BukkitPainting(toLocation(e.getLocation()), paint.getArt(), paint.getFacing(), e.getUniqueId()); + case DROPPED_ITEM: + return new BukkitItem(toLocation(e.getLocation()), ((Item)e).getItemStack(), e.getUniqueId()); + default: + return new BukkitEntity(toLocation(e.getLocation()), e.getType(), e.getUniqueId()); + } + } + + public static BaseBlock toBlock(LocalWorld world, ItemStack itemStack) throws WorldEditException { + final int typeId = itemStack.getTypeId(); + + switch (typeId) { + case ItemID.INK_SACK: + final Dye materialData = (Dye) itemStack.getData(); + if (materialData.getColor() == DyeColor.BROWN) { + return new BaseBlock(BlockID.COCOA_PLANT, -1); + } + break; + + case ItemID.HEAD: + return new SkullBlock(0, (byte) itemStack.getDurability()); + + default: + final BaseBlock baseBlock = BlockType.getBlockForItem(typeId, itemStack.getDurability()); + if (baseBlock != null) { + return baseBlock; + } + break; + } + + if (world.isValidBlockType(typeId)) { + return new BaseBlock(typeId, -1); + } + + throw new NotABlockException(typeId); + } +} diff --git a/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java similarity index 92% rename from src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index c7bf76097..9471bcd71 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -1,1371 +1,1328 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.bukkit; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.InputStream; -import java.lang.reflect.Method; -import java.net.URL; -import java.util.ArrayList; -import java.util.EnumMap; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.bukkit.Bukkit; -import org.bukkit.Effect; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.SkullType; -import org.bukkit.TreeType; -import org.bukkit.World; -import org.bukkit.block.Biome; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.block.BlockState; -import org.bukkit.block.Chest; -import org.bukkit.block.CreatureSpawner; -import org.bukkit.block.Furnace; -import org.bukkit.block.Sign; -import org.bukkit.block.Skull; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Ambient; -import org.bukkit.entity.Animals; -import org.bukkit.entity.Boat; -import org.bukkit.entity.Entity; -import org.bukkit.entity.ExperienceOrb; -import org.bukkit.entity.FallingBlock; -import org.bukkit.entity.Golem; -import org.bukkit.entity.Hanging; -import org.bukkit.entity.HumanEntity; -import org.bukkit.entity.Item; -import org.bukkit.entity.ItemFrame; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Minecart; -import org.bukkit.entity.Painting; -import org.bukkit.entity.Projectile; -import org.bukkit.entity.TNTPrimed; -import org.bukkit.entity.Tameable; -import org.bukkit.entity.Villager; -import org.bukkit.inventory.DoubleChestInventory; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemStack; -import org.bukkit.plugin.Plugin; - -import com.sk89q.worldedit.BiomeType; -import com.sk89q.worldedit.BlockVector2D; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.EntityType; -import com.sk89q.worldedit.LocalEntity; -import com.sk89q.worldedit.LocalWorld; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.Vector2D; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.blocks.BaseItemStack; -import com.sk89q.worldedit.blocks.BlockID; -import com.sk89q.worldedit.blocks.ContainerBlock; -import com.sk89q.worldedit.blocks.FurnaceBlock; -import com.sk89q.worldedit.blocks.MobSpawnerBlock; -import com.sk89q.worldedit.blocks.NoteBlock; -import com.sk89q.worldedit.blocks.SignBlock; -import com.sk89q.worldedit.blocks.SkullBlock; -import com.sk89q.worldedit.bukkit.entity.BukkitEntity; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.util.TreeGenerator; - -public class BukkitWorld extends LocalWorld { - - private static final Logger logger = WorldEdit.logger; - private World world; - private static boolean skipNmsAccess = false; - private static boolean skipNmsSafeSet = false; - private static boolean skipNmsValidBlockCheck = false; - - /* - * holder for the nmsblock class that we should use - */ - private static Class nmsBlockType; - private static Method nmsSetMethod; - private static Method nmsValidBlockMethod; - private static Method nmsGetMethod; - private static Method nmsSetSafeMethod; - - // copied from WG - private static > T tryEnum(Class enumType, String ... values) { - for (String val : values) { - try { - return Enum.valueOf(enumType, val); - } catch (IllegalArgumentException e) {} - } - return null; - } - private static org.bukkit.entity.EntityType tntMinecartType; - private static boolean checkMinecartType = true; - - /** - * Construct the object. - * @param world - */ - @SuppressWarnings("unchecked") - public BukkitWorld(World world) { - this.world = world; - - if (checkMinecartType) { - tntMinecartType = tryEnum(org.bukkit.entity.EntityType.class, "MINECART_TNT"); - checkMinecartType = false; - } - // check if we have a class we can use for nms access - - // only run once per server startup - if (nmsBlockType != null || skipNmsAccess || skipNmsSafeSet || skipNmsValidBlockCheck) return; - Plugin plugin = Bukkit.getPluginManager().getPlugin("WorldEdit"); - if (!(plugin instanceof WorldEditPlugin)) return; // hopefully never happens - WorldEditPlugin wePlugin = ((WorldEditPlugin) plugin); - File nmsBlocksDir = new File(wePlugin.getDataFolder() + File.separator + "nmsblocks" + File.separator); - if (nmsBlocksDir.listFiles() == null) { // no files to use - skipNmsAccess = true; skipNmsSafeSet = true; skipNmsValidBlockCheck = true; - return; - } - try { - // make a classloader that can handle our blocks - NmsBlockClassLoader loader = new NmsBlockClassLoader(BukkitWorld.class.getClassLoader(), nmsBlocksDir); - String filename; - for (File f : nmsBlocksDir.listFiles()) { - if (!f.isFile()) continue; - filename = f.getName(); - // load class using magic keyword - Class testBlock = null; - try { - testBlock = loader.loadClass("CL-NMS" + filename); - } catch (Throwable e) { - // someone is putting things where they don't belong - continue; - } - filename = filename.replaceFirst(".class$", ""); // get rid of extension - if (NmsBlock.class.isAssignableFrom(testBlock)) { - // got a NmsBlock, test it now - Class nmsClass = (Class) testBlock; - boolean canUse = false; - try { - canUse = (Boolean) nmsClass.getMethod("verify").invoke(null); - } catch (Throwable e) { - continue; - } - if (!canUse) continue; // not for this server - nmsBlockType = nmsClass; - nmsSetMethod = nmsBlockType.getMethod("set", World.class, Vector.class, BaseBlock.class); - nmsValidBlockMethod = nmsBlockType.getMethod("isValidBlockType", int.class); - nmsGetMethod = nmsBlockType.getMethod("get", World.class, Vector.class, int.class, int.class); - nmsSetSafeMethod = nmsBlockType.getMethod("setSafely", - BukkitWorld.class, Vector.class, com.sk89q.worldedit.foundation.Block.class, boolean.class); - // phew - break; - } - } - if (nmsBlockType != null) { - logger.info("[WorldEdit] Using external NmsBlock for this version: " + nmsBlockType.getName()); - } else { - // try our default - try { - nmsBlockType = (Class) Class.forName("com.sk89q.worldedit.bukkit.DefaultNmsBlock"); - boolean canUse = (Boolean) nmsBlockType.getMethod("verify").invoke(null); - if (canUse) { - nmsSetMethod = nmsBlockType.getMethod("set", World.class, Vector.class, BaseBlock.class); - nmsValidBlockMethod = nmsBlockType.getMethod("isValidBlockType", int.class); - nmsGetMethod = nmsBlockType.getMethod("get", World.class, Vector.class, int.class, int.class); - nmsSetSafeMethod = nmsBlockType.getMethod("setSafely", - BukkitWorld.class, Vector.class, com.sk89q.worldedit.foundation.Block.class, boolean.class); - logger.info("[WorldEdit] Using inbuilt NmsBlock for this version."); - } - } catch (Throwable e) { - // OMG DEVS WAI U NO SUPPORT SERVER - skipNmsAccess = true; skipNmsSafeSet = true; skipNmsValidBlockCheck = true; - logger.warning("[WorldEdit] No compatible nms block class found."); - } - } - } catch (Throwable e) { - logger.warning("[WorldEdit] Unable to load NmsBlock classes, make sure they are installed correctly."); - e.printStackTrace(); - skipNmsAccess = true; skipNmsSafeSet = true; skipNmsValidBlockCheck = true; - } - } - - private class NmsBlockClassLoader extends ClassLoader { - public File searchDir; - public NmsBlockClassLoader(ClassLoader parent, File searchDir) { - super(parent); - this.searchDir = searchDir; - } - - @Override - public Class loadClass(String name) throws ClassNotFoundException { - if (!name.startsWith("CL-NMS")) { - return super.loadClass(name); - } else { - name = name.replace("CL-NMS", ""); // hacky lol - } - try { - URL url = new File(searchDir, name).toURI().toURL(); - InputStream input = url.openConnection().getInputStream(); - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - - int data = input.read(); - while (data != -1) { - buffer.write(data); - data = input.read(); - } - input.close(); - - byte[] classData = buffer.toByteArray(); - - return defineClass(name.replaceFirst(".class$", ""), classData, 0, classData.length); - } catch (Throwable e) { - throw new ClassNotFoundException(); - } - } - } - - /** - * Get the world handle. - * - * @return - */ - public World getWorld() { - return world; - } - - /** - * Get the name of the world - * - * @return - */ - @Override - public String getName() { - return world.getName(); - } - - /** - * Set block type. - * - * @param pt - * @param type - * @return - */ - @Override - public boolean setBlockType(Vector pt, int type) { - return world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setTypeId(type); - } - - /** - * Set block type. - * - * @param pt - * @param type - * @return - */ - @Override - public boolean setBlockTypeFast(Vector pt, int type) { - return world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setTypeId(type, false); - } - - /** - * set block type & data - * @param pt - * @param type - * @param data - * @return - */ - @Override - public boolean setTypeIdAndData(Vector pt, int type, int data) { - return world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setTypeIdAndData(type, (byte) data, true); - } - - /** - * set block type & data - * @param pt - * @param type - * @param data - * @return - */ - @Override - public boolean setTypeIdAndDataFast(Vector pt, int type, int data) { - return world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setTypeIdAndData(type, (byte) data, false); - } - - /** - * Get block type. - * - * @param pt - * @return - */ - @Override - public int getBlockType(Vector pt) { - return world.getBlockTypeIdAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - } - - /** - * Set block data. - * - * @param pt - * @param data - */ - @Override - public void setBlockData(Vector pt, int data) { - world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setData((byte) data); - } - - /** - * Set block data. - * - * @param pt - * @param data - */ - @Override - public void setBlockDataFast(Vector pt, int data) { - world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setData((byte) data, false); - } - - /** - * Get block data. - * - * @param pt - * @return - */ - @Override - public int getBlockData(Vector pt) { - return world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).getData(); - } - - /** - * Get block light level. - * - * @param pt - * @return - */ - @Override - public int getBlockLightLevel(Vector pt) { - return world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).getLightLevel(); - } - - /** - * Get biome type - * - * @param pt - * @return - */ - @Override - public BiomeType getBiome(Vector2D pt) { - Biome bukkitBiome = world.getBiome(pt.getBlockX(), pt.getBlockZ()); - try { - return BukkitBiomeType.valueOf(bukkitBiome.name()); - } catch (IllegalArgumentException exc) { - return BiomeType.UNKNOWN; - } - } - - @Override - public void setBiome(Vector2D pt, BiomeType biome) { - if (biome instanceof BukkitBiomeType) { - Biome bukkitBiome; - bukkitBiome = ((BukkitBiomeType) biome).getBukkitBiome(); - world.setBiome(pt.getBlockX(), pt.getBlockZ(), bukkitBiome); - } - } - - /** - * Regenerate an area. - * - * @param region - * @param editSession - * @return - */ - @Override - public boolean regenerate(Region region, EditSession editSession) { - BaseBlock[] history = new BaseBlock[16 * 16 * (getMaxY() + 1)]; - - for (Vector2D chunk : region.getChunks()) { - Vector min = new Vector(chunk.getBlockX() * 16, 0, chunk.getBlockZ() * 16); - - // First save all the blocks inside - for (int x = 0; x < 16; ++x) { - for (int y = 0; y < (getMaxY() + 1); ++y) { - for (int z = 0; z < 16; ++z) { - Vector pt = min.add(x, y, z); - int index = y * 16 * 16 + z * 16 + x; - history[index] = editSession.getBlock(pt); - } - } - } - - try { - world.regenerateChunk(chunk.getBlockX(), chunk.getBlockZ()); - } catch (Throwable t) { - t.printStackTrace(); - } - - // Then restore - for (int x = 0; x < 16; ++x) { - for (int y = 0; y < (getMaxY() + 1); ++y) { - for (int z = 0; z < 16; ++z) { - Vector pt = min.add(x, y, z); - int index = y * 16 * 16 + z * 16 + x; - - // We have to restore the block if it was outside - if (!region.contains(pt)) { - editSession.smartSetBlock(pt, history[index]); - } else { // Otherwise fool with history - editSession.rememberChange(pt, history[index], - editSession.rawGetBlock(pt)); - } - } - } - } - } - - return true; - } - - /** - * Attempts to accurately copy a BaseBlock's extra data to the world. - * - * @param pt - * @param block - * @return - */ - @Override - public boolean copyToWorld(Vector pt, BaseBlock block) { - if (block instanceof SignBlock) { - // Signs - setSignText(pt, ((SignBlock) block).getText()); - return true; - } - - if (block instanceof FurnaceBlock) { - // Furnaces - Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (bukkitBlock == null) return false; - BlockState state = bukkitBlock.getState(); - if (!(state instanceof Furnace)) return false; - Furnace bukkit = (Furnace) state; - FurnaceBlock we = (FurnaceBlock) block; - bukkit.setBurnTime(we.getBurnTime()); - bukkit.setCookTime(we.getCookTime()); - return setContainerBlockContents(pt, ((ContainerBlock) block).getItems()); - } - - if (block instanceof ContainerBlock) { - // Chests/dispenser - return setContainerBlockContents(pt, ((ContainerBlock) block).getItems()); - } - - if (block instanceof MobSpawnerBlock) { - // Mob spawners - Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (bukkitBlock == null) return false; - BlockState state = bukkitBlock.getState(); - if (!(state instanceof CreatureSpawner)) return false; - CreatureSpawner bukkit = (CreatureSpawner) state; - MobSpawnerBlock we = (MobSpawnerBlock) block; - bukkit.setCreatureTypeByName(we.getMobType()); - bukkit.setDelay(we.getDelay()); - return true; - } - - if (block instanceof NoteBlock) { - // Note block - Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (bukkitBlock == null) return false; - BlockState state = bukkitBlock.getState(); - if (!(state instanceof org.bukkit.block.NoteBlock)) return false; - org.bukkit.block.NoteBlock bukkit = (org.bukkit.block.NoteBlock) state; - NoteBlock we = (NoteBlock) block; - bukkit.setRawNote(we.getNote()); - return true; - } - - if (block instanceof SkullBlock) { - // Skull block - Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (bukkitBlock == null) return false; - BlockState state = bukkitBlock.getState(); - if (!(state instanceof org.bukkit.block.Skull)) return false; - Skull bukkit = (Skull) state; - SkullBlock we = (SkullBlock) block; - // this is dumb - SkullType skullType = SkullType.SKELETON; - switch (we.getSkullType()) { - case 0: - skullType = SkullType.SKELETON; - break; - case 1: - skullType = SkullType.WITHER; - break; - case 2: - skullType = SkullType.ZOMBIE; - break; - case 3: - skullType = SkullType.PLAYER; - break; - case 4: - skullType = SkullType.CREEPER; - break; - } - bukkit.setSkullType(skullType); - BlockFace rotation; - switch (we.getRot()) { - // soooo dumb - case 0: - rotation = BlockFace.NORTH; - break; - case 1: - rotation = BlockFace.NORTH_NORTH_EAST; - break; - case 2: - rotation = BlockFace.NORTH_EAST; - break; - case 3: - rotation = BlockFace.EAST_NORTH_EAST; - break; - case 4: - rotation = BlockFace.EAST; - break; - case 5: - rotation = BlockFace.EAST_SOUTH_EAST; - break; - case 6: - rotation = BlockFace.SOUTH_EAST; - break; - case 7: - rotation = BlockFace.SOUTH_SOUTH_EAST; - break; - case 8: - rotation = BlockFace.SOUTH; - break; - case 9: - rotation = BlockFace.SOUTH_SOUTH_WEST; - break; - case 10: - rotation = BlockFace.SOUTH_WEST; - break; - case 11: - rotation = BlockFace.WEST_SOUTH_WEST; - break; - case 12: - rotation = BlockFace.WEST; - break; - case 13: - rotation = BlockFace.WEST_NORTH_WEST; - break; - case 14: - rotation = BlockFace.NORTH_WEST; - break; - case 15: - rotation = BlockFace.NORTH_NORTH_WEST; - break; - default: - rotation = BlockFace.NORTH; - break; - } - bukkit.setRotation(rotation); - if (we.getOwner() != null && !we.getOwner().isEmpty()) bukkit.setOwner(we.getOwner()); - bukkit.update(true); - return true; - } - - if (!skipNmsAccess) { - try { - return (Boolean) nmsSetMethod.invoke(null, world, pt, block); - } catch (Throwable t) { - logger.log(Level.WARNING, "WorldEdit: Failed to do NMS access for direct NBT data copy", t); - skipNmsAccess = true; - } - } - - return false; - } - - /** - * Attempts to read a BaseBlock's extra data from the world. - * - * @param pt - * @param block - * @return - */ - @Override - public boolean copyFromWorld(Vector pt, BaseBlock block) { - if (block instanceof SignBlock) { - // Signs - ((SignBlock) block).setText(getSignText(pt)); - return true; - } - - if (block instanceof FurnaceBlock) { - // Furnaces - Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (bukkitBlock == null) return false; - BlockState state = bukkitBlock.getState(); - if (!(state instanceof Furnace)) return false; - Furnace bukkit = (Furnace) state; - FurnaceBlock we = (FurnaceBlock) block; - we.setBurnTime(bukkit.getBurnTime()); - we.setCookTime(bukkit.getCookTime()); - ((ContainerBlock) block).setItems(getContainerBlockContents(pt)); - return true; - } - - if (block instanceof ContainerBlock) { - // Chests/dispenser - ((ContainerBlock) block).setItems(getContainerBlockContents(pt)); - return true; - } - - if (block instanceof MobSpawnerBlock) { - // Mob spawners - Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (bukkitBlock == null) return false; - BlockState state = bukkitBlock.getState(); - if (!(state instanceof CreatureSpawner)) return false; - CreatureSpawner bukkit = (CreatureSpawner) state; - MobSpawnerBlock we = (MobSpawnerBlock) block; - we.setMobType(bukkit.getCreatureTypeName()); - we.setDelay((short) bukkit.getDelay()); - return true; - } - - if (block instanceof NoteBlock) { - // Note block - Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (bukkitBlock == null) return false; - BlockState state = bukkitBlock.getState(); - if (!(state instanceof org.bukkit.block.NoteBlock)) return false; - org.bukkit.block.NoteBlock bukkit = (org.bukkit.block.NoteBlock) state; - NoteBlock we = (NoteBlock) block; - we.setNote(bukkit.getRawNote()); - return true; - } - - if (block instanceof SkullBlock) { - // Skull block - Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (bukkitBlock == null) return false; - BlockState state = bukkitBlock.getState(); - if (!(state instanceof org.bukkit.block.Skull)) return false; - Skull bukkit = (Skull) state; - SkullBlock we = (SkullBlock) block; - byte skullType = 0; - switch (bukkit.getSkullType()) { - // this is dumb but whoever wrote the class is stupid - case SKELETON: - skullType = 0; - break; - case WITHER: - skullType = 1; - break; - case ZOMBIE: - skullType = 2; - break; - case PLAYER: - skullType = 3; - break; - case CREEPER: - skullType = 4; - break; - } - we.setSkullType(skullType); - byte rot = 0; - switch (bukkit.getRotation()) { - // this is even more dumb, hurray for copy/paste - case NORTH: - rot = (byte) 0; - break; - case NORTH_NORTH_EAST: - rot = (byte) 1; - break; - case NORTH_EAST: - rot = (byte) 2; - break; - case EAST_NORTH_EAST: - rot = (byte) 3; - break; - case EAST: - rot = (byte) 4; - break; - case EAST_SOUTH_EAST: - rot = (byte) 5; - break; - case SOUTH_EAST: - rot = (byte) 6; - break; - case SOUTH_SOUTH_EAST: - rot = (byte) 7; - break; - case SOUTH: - rot = (byte) 8; - break; - case SOUTH_SOUTH_WEST: - rot = (byte) 9; - break; - case SOUTH_WEST: - rot = (byte) 10; - break; - case WEST_SOUTH_WEST: - rot = (byte) 11; - break; - case WEST: - rot = (byte) 12; - break; - case WEST_NORTH_WEST: - rot = (byte) 13; - break; - case NORTH_WEST: - rot = (byte) 14; - break; - case NORTH_NORTH_WEST: - rot = (byte) 15; - break; - } - we.setRot(rot); - we.setOwner(bukkit.hasOwner() ? bukkit.getOwner() : ""); - return true; - } - - return false; - } - - /** - * Gets the single block inventory for a potentially double chest. - * Handles people who have an old version of Bukkit. - * This should be replaced with {@link org.bukkit.block.Chest#getBlockInventory()} - * in a few months (now = March 2012) // note from future dev - lol - * - * @param chest The chest to get a single block inventory for - * @return The chest's inventory - */ - private Inventory getBlockInventory(Chest chest) { - try { - return chest.getBlockInventory(); - } catch (Throwable t) { - if (chest.getInventory() instanceof DoubleChestInventory) { - DoubleChestInventory inven = (DoubleChestInventory) chest.getInventory(); - if (inven.getLeftSide().getHolder().equals(chest)) { - return inven.getLeftSide(); - } else if (inven.getRightSide().getHolder().equals(chest)) { - return inven.getRightSide(); - } else { - return inven; - } - } else { - return chest.getInventory(); - } - } - } - - /** - * Clear a chest's contents. - * - * @param pt - */ - @Override - public boolean clearContainerBlockContents(Vector pt) { - Block block = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (block == null) { - return false; - } - BlockState state = block.getState(); - if (!(state instanceof org.bukkit.inventory.InventoryHolder)) { - return false; - } - - org.bukkit.inventory.InventoryHolder chest = (org.bukkit.inventory.InventoryHolder) state; - Inventory inven = chest.getInventory(); - if (chest instanceof Chest) { - inven = getBlockInventory((Chest) chest); - } - inven.clear(); - return true; - } - - /** - * Generate a tree at a location. - * - * @param pt - * @return - */ - @Override - @Deprecated - public boolean generateTree(EditSession editSession, Vector pt) { - return generateTree(TreeGenerator.TreeType.TREE, editSession, pt); - } - - /** - * Generate a big tree at a location. - * - * @param pt - * @return - */ - @Override - @Deprecated - public boolean generateBigTree(EditSession editSession, Vector pt) { - return generateTree(TreeGenerator.TreeType.BIG_TREE, editSession, pt); - } - - /** - * Generate a birch tree at a location. - * - * @param pt - * @return - */ - @Override - @Deprecated - public boolean generateBirchTree(EditSession editSession, Vector pt) { - return generateTree(TreeGenerator.TreeType.BIRCH, editSession, pt); - } - - /** - * Generate a redwood tree at a location. - * - * @param pt - * @return - */ - @Override - @Deprecated - public boolean generateRedwoodTree(EditSession editSession, Vector pt) { - return generateTree(TreeGenerator.TreeType.REDWOOD, editSession, pt); - } - - /** - * Generate a redwood tree at a location. - * - * @param pt - * @return - */ - @Override - @Deprecated - public boolean generateTallRedwoodTree(EditSession editSession, Vector pt) { - return generateTree(TreeGenerator.TreeType.TALL_REDWOOD, editSession, pt); - } - - /** - * An EnumMap that stores which WorldEdit TreeTypes apply to which Bukkit TreeTypes - */ - private static final EnumMap treeTypeMapping = - new EnumMap(TreeGenerator.TreeType.class); - - static { - for (TreeGenerator.TreeType type : TreeGenerator.TreeType.values()) { - try { - TreeType bukkitType = TreeType.valueOf(type.name()); - treeTypeMapping.put(type, bukkitType); - } catch (IllegalArgumentException e) { - // Unhandled TreeType - } - } - // Other mappings for WE-specific values - treeTypeMapping.put(TreeGenerator.TreeType.SHORT_JUNGLE, TreeType.SMALL_JUNGLE); - treeTypeMapping.put(TreeGenerator.TreeType.RANDOM, TreeType.BROWN_MUSHROOM); - treeTypeMapping.put(TreeGenerator.TreeType.RANDOM_REDWOOD, TreeType.REDWOOD); - treeTypeMapping.put(TreeGenerator.TreeType.PINE, TreeType.REDWOOD); - for (TreeGenerator.TreeType type : TreeGenerator.TreeType.values()) { - if (treeTypeMapping.get(type) == null) { - WorldEdit.logger.severe("No TreeType mapping for TreeGenerator.TreeType." + type); - } - } - } - - public static TreeType toBukkitTreeType(TreeGenerator.TreeType type) { - return treeTypeMapping.get(type); - } - - @Override - public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, Vector pt) { - TreeType bukkitType = toBukkitTreeType(type); - return type != null && world.generateTree(BukkitUtil.toLocation(world, pt), bukkitType, - new EditSessionBlockChangeDelegate(editSession)); - } - - /** - * Drop an item. - * - * @param pt - * @param item - */ - @Override - public void dropItem(Vector pt, BaseItemStack item) { - ItemStack bukkitItem = new ItemStack(item.getType(), item.getAmount(), - item.getData()); - world.dropItemNaturally(BukkitUtil.toLocation(world, pt), bukkitItem); - } - - /** - * Kill mobs in an area. - * - * @param origin The center of the area to kill mobs in. - * @param radius Maximum distance to kill mobs at; radius < 0 means kill all mobs - * @param flags various flags that determine what to kill - * @return number of mobs killed - */ - @Override - public int killMobs(Vector origin, double radius, int flags) { - boolean killPets = (flags & KillFlags.PETS) != 0; - boolean killNPCs = (flags & KillFlags.NPCS) != 0; - boolean killAnimals = (flags & KillFlags.ANIMALS) != 0; - boolean withLightning = (flags & KillFlags.WITH_LIGHTNING) != 0; - boolean killGolems = (flags & KillFlags.GOLEMS) != 0; - boolean killAmbient = (flags & KillFlags.AMBIENT) != 0; - - int num = 0; - double radiusSq = radius * radius; - - Location bukkitOrigin = BukkitUtil.toLocation(world, origin); - - for (LivingEntity ent : world.getLivingEntities()) { - if (ent instanceof HumanEntity) { - continue; - } - - if (!killAnimals && ent instanceof Animals) { - continue; - } - - if (!killPets && ent instanceof Tameable && ((Tameable) ent).isTamed()) { - continue; // tamed pet - } - - if (!killGolems && ent instanceof Golem) { - continue; - } - - if (!killNPCs && ent instanceof Villager) { - continue; - } - - if (!killAmbient && ent instanceof Ambient) { - continue; - } - - if (radius < 0 || bukkitOrigin.distanceSquared(ent.getLocation()) <= radiusSq) { - if (withLightning) { - world.strikeLightningEffect(ent.getLocation()); - } - ent.remove(); - ++num; - } - } - - return num; - } - - /** - * Remove entities in an area. - * - * @param origin - * @param radius - * @return - */ - @Override - public int removeEntities(EntityType type, Vector origin, int radius) { - int num = 0; - double radiusSq = Math.pow(radius, 2); - - for (Entity ent : world.getEntities()) { - if (radius != -1 - && origin.distanceSq(BukkitUtil.toVector(ent.getLocation())) > radiusSq) { - continue; - } - - switch (type) { - case ALL: - if (ent instanceof Projectile || ent instanceof Boat || ent instanceof Item - || ent instanceof FallingBlock || ent instanceof Minecart || ent instanceof Hanging - || ent instanceof TNTPrimed || ent instanceof ExperienceOrb) { - ent.remove(); - num++; - } - break; - - case PROJECTILES: - case ARROWS: - if (ent instanceof Projectile) { - // covers: arrow, egg, enderpearl, fireball, fish, snowball, throwpotion, thrownexpbottle - ent.remove(); - ++num; - } - break; - - case BOATS: - if (ent instanceof Boat) { - ent.remove(); - ++num; - } - break; - - case ITEMS: - if (ent instanceof Item) { - ent.remove(); - ++num; - } - break; - - case FALLING_BLOCKS: - if (ent instanceof FallingBlock) { - ent.remove(); - ++num; - } - break; - - case MINECARTS: - if (ent instanceof Minecart) { - ent.remove(); - ++num; - } - break; - - case PAINTINGS: - if (ent instanceof Painting) { - ent.remove(); - ++num; - } - break; - - case ITEM_FRAMES: - if (ent instanceof ItemFrame) { - ent.remove(); - ++num; - } - break; - - case TNT: - if (ent instanceof TNTPrimed || ent.getType() == tntMinecartType) { - ent.remove(); - ++num; - } - break; - - case XP_ORBS: - if (ent instanceof ExperienceOrb) { - ent.remove(); - ++num; - } - break; - } - } - - return num; - } - - /** - * Set a sign's text. - * - * @param pt - * @param text - * @return - */ - private boolean setSignText(Vector pt, String[] text) { - Block block = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (block == null) return false; - BlockState state = block.getState(); - if (state == null || !(state instanceof Sign)) return false; - Sign sign = (Sign) state; - sign.setLine(0, text[0]); - sign.setLine(1, text[1]); - sign.setLine(2, text[2]); - sign.setLine(3, text[3]); - sign.update(); - return true; - } - - /** - * Get a sign's text. - * - * @param pt - * @return - */ - private String[] getSignText(Vector pt) { - Block block = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (block == null) return new String[] { "", "", "", "" }; - BlockState state = block.getState(); - if (state == null || !(state instanceof Sign)) return new String[] { "", "", "", "" }; - Sign sign = (Sign) state; - String line0 = sign.getLine(0); - String line1 = sign.getLine(1); - String line2 = sign.getLine(2); - String line3 = sign.getLine(3); - return new String[] { - line0 != null ? line0 : "", - line1 != null ? line1 : "", - line2 != null ? line2 : "", - line3 != null ? line3 : "", - }; - } - - /** - * Get a container block's contents. - * - * @param pt - * @return - */ - private BaseItemStack[] getContainerBlockContents(Vector pt) { - Block block = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (block == null) { - return new BaseItemStack[0]; - } - BlockState state = block.getState(); - if (!(state instanceof org.bukkit.inventory.InventoryHolder)) { - return new BaseItemStack[0]; - } - - org.bukkit.inventory.InventoryHolder container = (org.bukkit.inventory.InventoryHolder) state; - Inventory inven = container.getInventory(); - if (container instanceof Chest) { - inven = getBlockInventory((Chest) container); - } - int size = inven.getSize(); - BaseItemStack[] contents = new BaseItemStack[size]; - - for (int i = 0; i < size; ++i) { - ItemStack bukkitStack = inven.getItem(i); - if (bukkitStack != null && bukkitStack.getTypeId() > 0) { - contents[i] = new BaseItemStack( - bukkitStack.getTypeId(), - bukkitStack.getAmount(), - bukkitStack.getDurability()); - try { - for (Map.Entry entry : bukkitStack.getEnchantments().entrySet()) { - contents[i].getEnchantments().put(entry.getKey().getId(), entry.getValue()); - } - } catch (Throwable ignore) {} - } - } - - return contents; - } - - /** - * Set a container block's contents. - * - * @param pt - * @param contents - * @return - */ - private boolean setContainerBlockContents(Vector pt, BaseItemStack[] contents) { - Block block = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (block == null) { - return false; - } - BlockState state = block.getState(); - if (!(state instanceof org.bukkit.inventory.InventoryHolder)) { - return false; - } - - org.bukkit.inventory.InventoryHolder chest = (org.bukkit.inventory.InventoryHolder) state; - Inventory inven = chest.getInventory(); - if (chest instanceof Chest) { - inven = getBlockInventory((Chest) chest); - } - int size = inven.getSize(); - - for (int i = 0; i < size; ++i) { - if (i >= contents.length) { - break; - } - - if (contents[i] != null) { - ItemStack toAdd = new ItemStack(contents[i].getType(), - contents[i].getAmount(), - contents[i].getData()); - try { - for (Map.Entry entry : contents[i].getEnchantments().entrySet()) { - toAdd.addEnchantment(Enchantment.getById(entry.getKey()), entry.getValue()); - } - } catch (Throwable ignore) {} - inven.setItem(i, toAdd); - } else { - inven.setItem(i, null); - } - } - - return true; - } - - /** - * Returns whether a block has a valid ID. - * - * @param type - * @return - */ - @Override - public boolean isValidBlockType(int type) { - if (!skipNmsValidBlockCheck) { - try { - return (Boolean) nmsValidBlockMethod.invoke(null, type); - } catch (Throwable e) { - skipNmsValidBlockCheck = true; - } - } - return Material.getMaterial(type) != null && Material.getMaterial(type).isBlock(); - } - - @Override - public void checkLoadedChunk(Vector pt) { - if (!world.isChunkLoaded(pt.getBlockX() >> 4, pt.getBlockZ() >> 4)) { - world.loadChunk(pt.getBlockX() >> 4, pt.getBlockZ() >> 4); - } - } - - @Override - public boolean equals(Object other) { - if (!(other instanceof BukkitWorld)) { - return false; - } - - return ((BukkitWorld) other).world.equals(world); - } - - @Override - public int hashCode() { - return world.hashCode(); - } - - @Override - public int getMaxY() { - return world.getMaxHeight() - 1; - } - - @Override - public void fixAfterFastMode(Iterable chunks) { - for (BlockVector2D chunkPos : chunks) { - world.refreshChunk(chunkPos.getBlockX(), chunkPos.getBlockZ()); - } - } - - private static final Map effects = new HashMap(); - static { - for (Effect effect : Effect.values()) { - effects.put(effect.getId(), effect); - } - } - - @Override - public boolean playEffect(Vector position, int type, int data) { - final Effect effect = effects.get(type); - if (effect == null) { - return false; - } - - world.playEffect(BukkitUtil.toLocation(world, position), effect, data); - - return true; - } - - @Override - public void simulateBlockMine(Vector pt) { - world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).breakNaturally(); - } - - @Override - public LocalEntity[] getEntities(Region region) { - List entities = new ArrayList(); - for (Vector2D pt : region.getChunks()) { - if (!world.isChunkLoaded(pt.getBlockX(), pt.getBlockZ())) { - continue; - } - - final Entity[] ents = world.getChunkAt(pt.getBlockX(), pt.getBlockZ()).getEntities(); - for (Entity ent : ents) { - if (region.contains(BukkitUtil.toVector(ent.getLocation()))) { - entities.add(BukkitUtil.toLocalEntity(ent)); - } - } - } - return entities.toArray(new BukkitEntity[entities.size()]); - } - - @Override - public int killEntities(LocalEntity... entities) { - int amount = 0; - Set toKill = new HashSet(); - for (LocalEntity entity : entities) { - toKill.add(((BukkitEntity) entity).getEntityId()); - } - for (Entity entity : world.getEntities()) { - if (toKill.contains(entity.getUniqueId())) { - entity.remove(); - ++amount; - } - } - return amount; - } - - @Override - public BaseBlock getBlock(Vector pt) { - int type = getBlockType(pt); - int data = getBlockData(pt); - - switch (type) { - case BlockID.WALL_SIGN: - case BlockID.SIGN_POST: - //case BlockID.CHEST: // Prevent data loss for now - //case BlockID.FURNACE: - //case BlockID.BURNING_FURNACE: - //case BlockID.DISPENSER: - //case BlockID.MOB_SPAWNER: - case BlockID.NOTE_BLOCK: - case BlockID.HEAD: - return super.getBlock(pt); - default: - if (!skipNmsAccess) { - try { - NmsBlock block = null; - block = (NmsBlock) nmsGetMethod.invoke(null, getWorld(), pt, type, data); - if (block != null) { - return block; - } - } catch (Throwable t) { - logger.log(Level.WARNING, - "WorldEdit: Failed to do NMS access for direct NBT data copy", t); - skipNmsAccess = true; - } - } - } - - return super.getBlock(pt); - } - - @Override - public boolean setBlock(Vector pt, com.sk89q.worldedit.foundation.Block block, boolean notifyAdjacent) { - if (!skipNmsSafeSet) { - try { - return (Boolean) nmsSetSafeMethod.invoke(null, this, pt, block, notifyAdjacent); - } catch (Throwable t) { - logger.log(Level.WARNING, "WorldEdit: Failed to do NMS safe block set", t); - skipNmsSafeSet = true; - } - } - - return super.setBlock(pt, block, notifyAdjacent); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.bukkit; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.EntityType; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.*; +import com.sk89q.worldedit.blocks.ContainerBlock; +import com.sk89q.worldedit.blocks.NoteBlock; +import com.sk89q.worldedit.bukkit.entity.BukkitEntity; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.TreeGenerator; +import org.bukkit.*; +import org.bukkit.Location; +import org.bukkit.block.*; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.*; +import org.bukkit.inventory.DoubleChestInventory; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.Plugin; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.InputStream; +import java.lang.reflect.Method; +import java.net.URL; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class BukkitWorld extends LocalWorld { + + private static final Logger logger = WorldEdit.logger; + private World world; + private static boolean skipNmsAccess = false; + private static boolean skipNmsSafeSet = false; + private static boolean skipNmsValidBlockCheck = false; + + /* + * holder for the nmsblock class that we should use + */ + private static Class nmsBlockType; + private static Method nmsSetMethod; + private static Method nmsValidBlockMethod; + private static Method nmsGetMethod; + private static Method nmsSetSafeMethod; + + // copied from WG + private static > T tryEnum(Class enumType, String ... values) { + for (String val : values) { + try { + return Enum.valueOf(enumType, val); + } catch (IllegalArgumentException e) {} + } + return null; + } + private static org.bukkit.entity.EntityType tntMinecartType; + private static boolean checkMinecartType = true; + + /** + * Construct the object. + * @param world + */ + @SuppressWarnings("unchecked") + public BukkitWorld(World world) { + this.world = world; + + if (checkMinecartType) { + tntMinecartType = tryEnum(org.bukkit.entity.EntityType.class, "MINECART_TNT"); + checkMinecartType = false; + } + // check if we have a class we can use for nms access + + // only run once per server startup + if (nmsBlockType != null || skipNmsAccess || skipNmsSafeSet || skipNmsValidBlockCheck) return; + Plugin plugin = Bukkit.getPluginManager().getPlugin("WorldEdit"); + if (!(plugin instanceof WorldEditPlugin)) return; // hopefully never happens + WorldEditPlugin wePlugin = ((WorldEditPlugin) plugin); + File nmsBlocksDir = new File(wePlugin.getDataFolder() + File.separator + "nmsblocks" + File.separator); + if (nmsBlocksDir.listFiles() == null) { // no files to use + skipNmsAccess = true; skipNmsSafeSet = true; skipNmsValidBlockCheck = true; + return; + } + try { + // make a classloader that can handle our blocks + NmsBlockClassLoader loader = new NmsBlockClassLoader(BukkitWorld.class.getClassLoader(), nmsBlocksDir); + String filename; + for (File f : nmsBlocksDir.listFiles()) { + if (!f.isFile()) continue; + filename = f.getName(); + // load class using magic keyword + Class testBlock = null; + try { + testBlock = loader.loadClass("CL-NMS" + filename); + } catch (Throwable e) { + // someone is putting things where they don't belong + continue; + } + filename = filename.replaceFirst(".class$", ""); // get rid of extension + if (NmsBlock.class.isAssignableFrom(testBlock)) { + // got a NmsBlock, test it now + Class nmsClass = (Class) testBlock; + boolean canUse = false; + try { + canUse = (Boolean) nmsClass.getMethod("verify").invoke(null); + } catch (Throwable e) { + continue; + } + if (!canUse) continue; // not for this server + nmsBlockType = nmsClass; + nmsSetMethod = nmsBlockType.getMethod("set", World.class, Vector.class, BaseBlock.class); + nmsValidBlockMethod = nmsBlockType.getMethod("isValidBlockType", int.class); + nmsGetMethod = nmsBlockType.getMethod("get", World.class, Vector.class, int.class, int.class); + nmsSetSafeMethod = nmsBlockType.getMethod("setSafely", + BukkitWorld.class, Vector.class, com.sk89q.worldedit.foundation.Block.class, boolean.class); + // phew + break; + } + } + if (nmsBlockType != null) { + logger.info("[WorldEdit] Using external NmsBlock for this version: " + nmsBlockType.getName()); + } else { + // try our default + try { + nmsBlockType = (Class) Class.forName("com.sk89q.worldedit.bukkit.DefaultNmsBlock"); + boolean canUse = (Boolean) nmsBlockType.getMethod("verify").invoke(null); + if (canUse) { + nmsSetMethod = nmsBlockType.getMethod("set", World.class, Vector.class, BaseBlock.class); + nmsValidBlockMethod = nmsBlockType.getMethod("isValidBlockType", int.class); + nmsGetMethod = nmsBlockType.getMethod("get", World.class, Vector.class, int.class, int.class); + nmsSetSafeMethod = nmsBlockType.getMethod("setSafely", + BukkitWorld.class, Vector.class, com.sk89q.worldedit.foundation.Block.class, boolean.class); + logger.info("[WorldEdit] Using inbuilt NmsBlock for this version."); + } + } catch (Throwable e) { + // OMG DEVS WAI U NO SUPPORT SERVER + skipNmsAccess = true; skipNmsSafeSet = true; skipNmsValidBlockCheck = true; + logger.warning("[WorldEdit] No compatible nms block class found."); + } + } + } catch (Throwable e) { + logger.warning("[WorldEdit] Unable to load NmsBlock classes, make sure they are installed correctly."); + e.printStackTrace(); + skipNmsAccess = true; skipNmsSafeSet = true; skipNmsValidBlockCheck = true; + } + } + + private class NmsBlockClassLoader extends ClassLoader { + public File searchDir; + public NmsBlockClassLoader(ClassLoader parent, File searchDir) { + super(parent); + this.searchDir = searchDir; + } + + @Override + public Class loadClass(String name) throws ClassNotFoundException { + if (!name.startsWith("CL-NMS")) { + return super.loadClass(name); + } else { + name = name.replace("CL-NMS", ""); // hacky lol + } + try { + URL url = new File(searchDir, name).toURI().toURL(); + InputStream input = url.openConnection().getInputStream(); + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + + int data = input.read(); + while (data != -1) { + buffer.write(data); + data = input.read(); + } + input.close(); + + byte[] classData = buffer.toByteArray(); + + return defineClass(name.replaceFirst(".class$", ""), classData, 0, classData.length); + } catch (Throwable e) { + throw new ClassNotFoundException(); + } + } + } + + /** + * Get the world handle. + * + * @return + */ + public World getWorld() { + return world; + } + + /** + * Get the name of the world + * + * @return + */ + @Override + public String getName() { + return world.getName(); + } + + /** + * Set block type. + * + * @param pt + * @param type + * @return + */ + @Override + public boolean setBlockType(Vector pt, int type) { + return world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setTypeId(type); + } + + /** + * Set block type. + * + * @param pt + * @param type + * @return + */ + @Override + public boolean setBlockTypeFast(Vector pt, int type) { + return world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setTypeId(type, false); + } + + /** + * set block type & data + * @param pt + * @param type + * @param data + * @return + */ + @Override + public boolean setTypeIdAndData(Vector pt, int type, int data) { + return world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setTypeIdAndData(type, (byte) data, true); + } + + /** + * set block type & data + * @param pt + * @param type + * @param data + * @return + */ + @Override + public boolean setTypeIdAndDataFast(Vector pt, int type, int data) { + return world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setTypeIdAndData(type, (byte) data, false); + } + + /** + * Get block type. + * + * @param pt + * @return + */ + @Override + public int getBlockType(Vector pt) { + return world.getBlockTypeIdAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + } + + /** + * Set block data. + * + * @param pt + * @param data + */ + @Override + public void setBlockData(Vector pt, int data) { + world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setData((byte) data); + } + + /** + * Set block data. + * + * @param pt + * @param data + */ + @Override + public void setBlockDataFast(Vector pt, int data) { + world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setData((byte) data, false); + } + + /** + * Get block data. + * + * @param pt + * @return + */ + @Override + public int getBlockData(Vector pt) { + return world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).getData(); + } + + /** + * Get block light level. + * + * @param pt + * @return + */ + @Override + public int getBlockLightLevel(Vector pt) { + return world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).getLightLevel(); + } + + /** + * Get biome type + * + * @param pt + * @return + */ + @Override + public BiomeType getBiome(Vector2D pt) { + Biome bukkitBiome = world.getBiome(pt.getBlockX(), pt.getBlockZ()); + try { + return BukkitBiomeType.valueOf(bukkitBiome.name()); + } catch (IllegalArgumentException exc) { + return BiomeType.UNKNOWN; + } + } + + @Override + public void setBiome(Vector2D pt, BiomeType biome) { + if (biome instanceof BukkitBiomeType) { + Biome bukkitBiome; + bukkitBiome = ((BukkitBiomeType) biome).getBukkitBiome(); + world.setBiome(pt.getBlockX(), pt.getBlockZ(), bukkitBiome); + } + } + + /** + * Regenerate an area. + * + * @param region + * @param editSession + * @return + */ + @Override + public boolean regenerate(Region region, EditSession editSession) { + BaseBlock[] history = new BaseBlock[16 * 16 * (getMaxY() + 1)]; + + for (Vector2D chunk : region.getChunks()) { + Vector min = new Vector(chunk.getBlockX() * 16, 0, chunk.getBlockZ() * 16); + + // First save all the blocks inside + for (int x = 0; x < 16; ++x) { + for (int y = 0; y < (getMaxY() + 1); ++y) { + for (int z = 0; z < 16; ++z) { + Vector pt = min.add(x, y, z); + int index = y * 16 * 16 + z * 16 + x; + history[index] = editSession.getBlock(pt); + } + } + } + + try { + world.regenerateChunk(chunk.getBlockX(), chunk.getBlockZ()); + } catch (Throwable t) { + t.printStackTrace(); + } + + // Then restore + for (int x = 0; x < 16; ++x) { + for (int y = 0; y < (getMaxY() + 1); ++y) { + for (int z = 0; z < 16; ++z) { + Vector pt = min.add(x, y, z); + int index = y * 16 * 16 + z * 16 + x; + + // We have to restore the block if it was outside + if (!region.contains(pt)) { + editSession.smartSetBlock(pt, history[index]); + } else { // Otherwise fool with history + editSession.rememberChange(pt, history[index], + editSession.rawGetBlock(pt)); + } + } + } + } + } + + return true; + } + + /** + * Attempts to accurately copy a BaseBlock's extra data to the world. + * + * @param pt + * @param block + * @return + */ + @Override + public boolean copyToWorld(Vector pt, BaseBlock block) { + if (block instanceof SignBlock) { + // Signs + setSignText(pt, ((SignBlock) block).getText()); + return true; + } + + if (block instanceof FurnaceBlock) { + // Furnaces + Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + if (bukkitBlock == null) return false; + BlockState state = bukkitBlock.getState(); + if (!(state instanceof Furnace)) return false; + Furnace bukkit = (Furnace) state; + FurnaceBlock we = (FurnaceBlock) block; + bukkit.setBurnTime(we.getBurnTime()); + bukkit.setCookTime(we.getCookTime()); + return setContainerBlockContents(pt, ((ContainerBlock) block).getItems()); + } + + if (block instanceof ContainerBlock) { + // Chests/dispenser + return setContainerBlockContents(pt, ((ContainerBlock) block).getItems()); + } + + if (block instanceof MobSpawnerBlock) { + // Mob spawners + Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + if (bukkitBlock == null) return false; + BlockState state = bukkitBlock.getState(); + if (!(state instanceof CreatureSpawner)) return false; + CreatureSpawner bukkit = (CreatureSpawner) state; + MobSpawnerBlock we = (MobSpawnerBlock) block; + bukkit.setCreatureTypeByName(we.getMobType()); + bukkit.setDelay(we.getDelay()); + return true; + } + + if (block instanceof NoteBlock) { + // Note block + Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + if (bukkitBlock == null) return false; + BlockState state = bukkitBlock.getState(); + if (!(state instanceof org.bukkit.block.NoteBlock)) return false; + org.bukkit.block.NoteBlock bukkit = (org.bukkit.block.NoteBlock) state; + NoteBlock we = (NoteBlock) block; + bukkit.setRawNote(we.getNote()); + return true; + } + + if (block instanceof SkullBlock) { + // Skull block + Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + if (bukkitBlock == null) return false; + BlockState state = bukkitBlock.getState(); + if (!(state instanceof org.bukkit.block.Skull)) return false; + Skull bukkit = (Skull) state; + SkullBlock we = (SkullBlock) block; + // this is dumb + SkullType skullType = SkullType.SKELETON; + switch (we.getSkullType()) { + case 0: + skullType = SkullType.SKELETON; + break; + case 1: + skullType = SkullType.WITHER; + break; + case 2: + skullType = SkullType.ZOMBIE; + break; + case 3: + skullType = SkullType.PLAYER; + break; + case 4: + skullType = SkullType.CREEPER; + break; + } + bukkit.setSkullType(skullType); + BlockFace rotation; + switch (we.getRot()) { + // soooo dumb + case 0: + rotation = BlockFace.NORTH; + break; + case 1: + rotation = BlockFace.NORTH_NORTH_EAST; + break; + case 2: + rotation = BlockFace.NORTH_EAST; + break; + case 3: + rotation = BlockFace.EAST_NORTH_EAST; + break; + case 4: + rotation = BlockFace.EAST; + break; + case 5: + rotation = BlockFace.EAST_SOUTH_EAST; + break; + case 6: + rotation = BlockFace.SOUTH_EAST; + break; + case 7: + rotation = BlockFace.SOUTH_SOUTH_EAST; + break; + case 8: + rotation = BlockFace.SOUTH; + break; + case 9: + rotation = BlockFace.SOUTH_SOUTH_WEST; + break; + case 10: + rotation = BlockFace.SOUTH_WEST; + break; + case 11: + rotation = BlockFace.WEST_SOUTH_WEST; + break; + case 12: + rotation = BlockFace.WEST; + break; + case 13: + rotation = BlockFace.WEST_NORTH_WEST; + break; + case 14: + rotation = BlockFace.NORTH_WEST; + break; + case 15: + rotation = BlockFace.NORTH_NORTH_WEST; + break; + default: + rotation = BlockFace.NORTH; + break; + } + bukkit.setRotation(rotation); + if (we.getOwner() != null && !we.getOwner().isEmpty()) bukkit.setOwner(we.getOwner()); + bukkit.update(true); + return true; + } + + if (!skipNmsAccess) { + try { + return (Boolean) nmsSetMethod.invoke(null, world, pt, block); + } catch (Throwable t) { + logger.log(Level.WARNING, "WorldEdit: Failed to do NMS access for direct NBT data copy", t); + skipNmsAccess = true; + } + } + + return false; + } + + /** + * Attempts to read a BaseBlock's extra data from the world. + * + * @param pt + * @param block + * @return + */ + @Override + public boolean copyFromWorld(Vector pt, BaseBlock block) { + if (block instanceof SignBlock) { + // Signs + ((SignBlock) block).setText(getSignText(pt)); + return true; + } + + if (block instanceof FurnaceBlock) { + // Furnaces + Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + if (bukkitBlock == null) return false; + BlockState state = bukkitBlock.getState(); + if (!(state instanceof Furnace)) return false; + Furnace bukkit = (Furnace) state; + FurnaceBlock we = (FurnaceBlock) block; + we.setBurnTime(bukkit.getBurnTime()); + we.setCookTime(bukkit.getCookTime()); + ((ContainerBlock) block).setItems(getContainerBlockContents(pt)); + return true; + } + + if (block instanceof ContainerBlock) { + // Chests/dispenser + ((ContainerBlock) block).setItems(getContainerBlockContents(pt)); + return true; + } + + if (block instanceof MobSpawnerBlock) { + // Mob spawners + Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + if (bukkitBlock == null) return false; + BlockState state = bukkitBlock.getState(); + if (!(state instanceof CreatureSpawner)) return false; + CreatureSpawner bukkit = (CreatureSpawner) state; + MobSpawnerBlock we = (MobSpawnerBlock) block; + we.setMobType(bukkit.getCreatureTypeName()); + we.setDelay((short) bukkit.getDelay()); + return true; + } + + if (block instanceof NoteBlock) { + // Note block + Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + if (bukkitBlock == null) return false; + BlockState state = bukkitBlock.getState(); + if (!(state instanceof org.bukkit.block.NoteBlock)) return false; + org.bukkit.block.NoteBlock bukkit = (org.bukkit.block.NoteBlock) state; + NoteBlock we = (NoteBlock) block; + we.setNote(bukkit.getRawNote()); + return true; + } + + if (block instanceof SkullBlock) { + // Skull block + Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + if (bukkitBlock == null) return false; + BlockState state = bukkitBlock.getState(); + if (!(state instanceof org.bukkit.block.Skull)) return false; + Skull bukkit = (Skull) state; + SkullBlock we = (SkullBlock) block; + byte skullType = 0; + switch (bukkit.getSkullType()) { + // this is dumb but whoever wrote the class is stupid + case SKELETON: + skullType = 0; + break; + case WITHER: + skullType = 1; + break; + case ZOMBIE: + skullType = 2; + break; + case PLAYER: + skullType = 3; + break; + case CREEPER: + skullType = 4; + break; + } + we.setSkullType(skullType); + byte rot = 0; + switch (bukkit.getRotation()) { + // this is even more dumb, hurray for copy/paste + case NORTH: + rot = (byte) 0; + break; + case NORTH_NORTH_EAST: + rot = (byte) 1; + break; + case NORTH_EAST: + rot = (byte) 2; + break; + case EAST_NORTH_EAST: + rot = (byte) 3; + break; + case EAST: + rot = (byte) 4; + break; + case EAST_SOUTH_EAST: + rot = (byte) 5; + break; + case SOUTH_EAST: + rot = (byte) 6; + break; + case SOUTH_SOUTH_EAST: + rot = (byte) 7; + break; + case SOUTH: + rot = (byte) 8; + break; + case SOUTH_SOUTH_WEST: + rot = (byte) 9; + break; + case SOUTH_WEST: + rot = (byte) 10; + break; + case WEST_SOUTH_WEST: + rot = (byte) 11; + break; + case WEST: + rot = (byte) 12; + break; + case WEST_NORTH_WEST: + rot = (byte) 13; + break; + case NORTH_WEST: + rot = (byte) 14; + break; + case NORTH_NORTH_WEST: + rot = (byte) 15; + break; + } + we.setRot(rot); + we.setOwner(bukkit.hasOwner() ? bukkit.getOwner() : ""); + return true; + } + + return false; + } + + /** + * Gets the single block inventory for a potentially double chest. + * Handles people who have an old version of Bukkit. + * This should be replaced with {@link org.bukkit.block.Chest#getBlockInventory()} + * in a few months (now = March 2012) // note from future dev - lol + * + * @param chest The chest to get a single block inventory for + * @return The chest's inventory + */ + private Inventory getBlockInventory(Chest chest) { + try { + return chest.getBlockInventory(); + } catch (Throwable t) { + if (chest.getInventory() instanceof DoubleChestInventory) { + DoubleChestInventory inven = (DoubleChestInventory) chest.getInventory(); + if (inven.getLeftSide().getHolder().equals(chest)) { + return inven.getLeftSide(); + } else if (inven.getRightSide().getHolder().equals(chest)) { + return inven.getRightSide(); + } else { + return inven; + } + } else { + return chest.getInventory(); + } + } + } + + /** + * Clear a chest's contents. + * + * @param pt + */ + @Override + public boolean clearContainerBlockContents(Vector pt) { + Block block = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + if (block == null) { + return false; + } + BlockState state = block.getState(); + if (!(state instanceof org.bukkit.inventory.InventoryHolder)) { + return false; + } + + org.bukkit.inventory.InventoryHolder chest = (org.bukkit.inventory.InventoryHolder) state; + Inventory inven = chest.getInventory(); + if (chest instanceof Chest) { + inven = getBlockInventory((Chest) chest); + } + inven.clear(); + return true; + } + + /** + * Generate a tree at a location. + * + * @param pt + * @return + */ + @Override + @Deprecated + public boolean generateTree(EditSession editSession, Vector pt) { + return generateTree(TreeGenerator.TreeType.TREE, editSession, pt); + } + + /** + * Generate a big tree at a location. + * + * @param pt + * @return + */ + @Override + @Deprecated + public boolean generateBigTree(EditSession editSession, Vector pt) { + return generateTree(TreeGenerator.TreeType.BIG_TREE, editSession, pt); + } + + /** + * Generate a birch tree at a location. + * + * @param pt + * @return + */ + @Override + @Deprecated + public boolean generateBirchTree(EditSession editSession, Vector pt) { + return generateTree(TreeGenerator.TreeType.BIRCH, editSession, pt); + } + + /** + * Generate a redwood tree at a location. + * + * @param pt + * @return + */ + @Override + @Deprecated + public boolean generateRedwoodTree(EditSession editSession, Vector pt) { + return generateTree(TreeGenerator.TreeType.REDWOOD, editSession, pt); + } + + /** + * Generate a redwood tree at a location. + * + * @param pt + * @return + */ + @Override + @Deprecated + public boolean generateTallRedwoodTree(EditSession editSession, Vector pt) { + return generateTree(TreeGenerator.TreeType.TALL_REDWOOD, editSession, pt); + } + + /** + * An EnumMap that stores which WorldEdit TreeTypes apply to which Bukkit TreeTypes + */ + private static final EnumMap treeTypeMapping = + new EnumMap(TreeGenerator.TreeType.class); + + static { + for (TreeGenerator.TreeType type : TreeGenerator.TreeType.values()) { + try { + TreeType bukkitType = TreeType.valueOf(type.name()); + treeTypeMapping.put(type, bukkitType); + } catch (IllegalArgumentException e) { + // Unhandled TreeType + } + } + // Other mappings for WE-specific values + treeTypeMapping.put(TreeGenerator.TreeType.SHORT_JUNGLE, TreeType.SMALL_JUNGLE); + treeTypeMapping.put(TreeGenerator.TreeType.RANDOM, TreeType.BROWN_MUSHROOM); + treeTypeMapping.put(TreeGenerator.TreeType.RANDOM_REDWOOD, TreeType.REDWOOD); + treeTypeMapping.put(TreeGenerator.TreeType.PINE, TreeType.REDWOOD); + for (TreeGenerator.TreeType type : TreeGenerator.TreeType.values()) { + if (treeTypeMapping.get(type) == null) { + WorldEdit.logger.severe("No TreeType mapping for TreeGenerator.TreeType." + type); + } + } + } + + public static TreeType toBukkitTreeType(TreeGenerator.TreeType type) { + return treeTypeMapping.get(type); + } + + @Override + public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, Vector pt) { + TreeType bukkitType = toBukkitTreeType(type); + return type != null && world.generateTree(BukkitUtil.toLocation(world, pt), bukkitType, + new EditSessionBlockChangeDelegate(editSession)); + } + + /** + * Drop an item. + * + * @param pt + * @param item + */ + @Override + public void dropItem(Vector pt, BaseItemStack item) { + ItemStack bukkitItem = new ItemStack(item.getType(), item.getAmount(), + item.getData()); + world.dropItemNaturally(BukkitUtil.toLocation(world, pt), bukkitItem); + } + + /** + * Kill mobs in an area. + * + * @param origin The center of the area to kill mobs in. + * @param radius Maximum distance to kill mobs at; radius < 0 means kill all mobs + * @param flags various flags that determine what to kill + * @return number of mobs killed + */ + @Override + public int killMobs(Vector origin, double radius, int flags) { + boolean killPets = (flags & KillFlags.PETS) != 0; + boolean killNPCs = (flags & KillFlags.NPCS) != 0; + boolean killAnimals = (flags & KillFlags.ANIMALS) != 0; + boolean withLightning = (flags & KillFlags.WITH_LIGHTNING) != 0; + boolean killGolems = (flags & KillFlags.GOLEMS) != 0; + boolean killAmbient = (flags & KillFlags.AMBIENT) != 0; + + int num = 0; + double radiusSq = radius * radius; + + Location bukkitOrigin = BukkitUtil.toLocation(world, origin); + + for (LivingEntity ent : world.getLivingEntities()) { + if (ent instanceof HumanEntity) { + continue; + } + + if (!killAnimals && ent instanceof Animals) { + continue; + } + + if (!killPets && ent instanceof Tameable && ((Tameable) ent).isTamed()) { + continue; // tamed pet + } + + if (!killGolems && ent instanceof Golem) { + continue; + } + + if (!killNPCs && ent instanceof Villager) { + continue; + } + + if (!killAmbient && ent instanceof Ambient) { + continue; + } + + if (radius < 0 || bukkitOrigin.distanceSquared(ent.getLocation()) <= radiusSq) { + if (withLightning) { + world.strikeLightningEffect(ent.getLocation()); + } + ent.remove(); + ++num; + } + } + + return num; + } + + /** + * Remove entities in an area. + * + * @param origin + * @param radius + * @return + */ + @Override + public int removeEntities(EntityType type, Vector origin, int radius) { + int num = 0; + double radiusSq = Math.pow(radius, 2); + + for (Entity ent : world.getEntities()) { + if (radius != -1 + && origin.distanceSq(BukkitUtil.toVector(ent.getLocation())) > radiusSq) { + continue; + } + + switch (type) { + case ALL: + if (ent instanceof Projectile || ent instanceof Boat || ent instanceof Item + || ent instanceof FallingBlock || ent instanceof Minecart || ent instanceof Hanging + || ent instanceof TNTPrimed || ent instanceof ExperienceOrb) { + ent.remove(); + num++; + } + break; + + case PROJECTILES: + case ARROWS: + if (ent instanceof Projectile) { + // covers: arrow, egg, enderpearl, fireball, fish, snowball, throwpotion, thrownexpbottle + ent.remove(); + ++num; + } + break; + + case BOATS: + if (ent instanceof Boat) { + ent.remove(); + ++num; + } + break; + + case ITEMS: + if (ent instanceof Item) { + ent.remove(); + ++num; + } + break; + + case FALLING_BLOCKS: + if (ent instanceof FallingBlock) { + ent.remove(); + ++num; + } + break; + + case MINECARTS: + if (ent instanceof Minecart) { + ent.remove(); + ++num; + } + break; + + case PAINTINGS: + if (ent instanceof Painting) { + ent.remove(); + ++num; + } + break; + + case ITEM_FRAMES: + if (ent instanceof ItemFrame) { + ent.remove(); + ++num; + } + break; + + case TNT: + if (ent instanceof TNTPrimed || ent.getType() == tntMinecartType) { + ent.remove(); + ++num; + } + break; + + case XP_ORBS: + if (ent instanceof ExperienceOrb) { + ent.remove(); + ++num; + } + break; + } + } + + return num; + } + + /** + * Set a sign's text. + * + * @param pt + * @param text + * @return + */ + private boolean setSignText(Vector pt, String[] text) { + Block block = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + if (block == null) return false; + BlockState state = block.getState(); + if (state == null || !(state instanceof Sign)) return false; + Sign sign = (Sign) state; + sign.setLine(0, text[0]); + sign.setLine(1, text[1]); + sign.setLine(2, text[2]); + sign.setLine(3, text[3]); + sign.update(); + return true; + } + + /** + * Get a sign's text. + * + * @param pt + * @return + */ + private String[] getSignText(Vector pt) { + Block block = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + if (block == null) return new String[] { "", "", "", "" }; + BlockState state = block.getState(); + if (state == null || !(state instanceof Sign)) return new String[] { "", "", "", "" }; + Sign sign = (Sign) state; + String line0 = sign.getLine(0); + String line1 = sign.getLine(1); + String line2 = sign.getLine(2); + String line3 = sign.getLine(3); + return new String[] { + line0 != null ? line0 : "", + line1 != null ? line1 : "", + line2 != null ? line2 : "", + line3 != null ? line3 : "", + }; + } + + /** + * Get a container block's contents. + * + * @param pt + * @return + */ + private BaseItemStack[] getContainerBlockContents(Vector pt) { + Block block = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + if (block == null) { + return new BaseItemStack[0]; + } + BlockState state = block.getState(); + if (!(state instanceof org.bukkit.inventory.InventoryHolder)) { + return new BaseItemStack[0]; + } + + org.bukkit.inventory.InventoryHolder container = (org.bukkit.inventory.InventoryHolder) state; + Inventory inven = container.getInventory(); + if (container instanceof Chest) { + inven = getBlockInventory((Chest) container); + } + int size = inven.getSize(); + BaseItemStack[] contents = new BaseItemStack[size]; + + for (int i = 0; i < size; ++i) { + ItemStack bukkitStack = inven.getItem(i); + if (bukkitStack != null && bukkitStack.getTypeId() > 0) { + contents[i] = new BaseItemStack( + bukkitStack.getTypeId(), + bukkitStack.getAmount(), + bukkitStack.getDurability()); + try { + for (Map.Entry entry : bukkitStack.getEnchantments().entrySet()) { + contents[i].getEnchantments().put(entry.getKey().getId(), entry.getValue()); + } + } catch (Throwable ignore) {} + } + } + + return contents; + } + + /** + * Set a container block's contents. + * + * @param pt + * @param contents + * @return + */ + private boolean setContainerBlockContents(Vector pt, BaseItemStack[] contents) { + Block block = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + if (block == null) { + return false; + } + BlockState state = block.getState(); + if (!(state instanceof org.bukkit.inventory.InventoryHolder)) { + return false; + } + + org.bukkit.inventory.InventoryHolder chest = (org.bukkit.inventory.InventoryHolder) state; + Inventory inven = chest.getInventory(); + if (chest instanceof Chest) { + inven = getBlockInventory((Chest) chest); + } + int size = inven.getSize(); + + for (int i = 0; i < size; ++i) { + if (i >= contents.length) { + break; + } + + if (contents[i] != null) { + ItemStack toAdd = new ItemStack(contents[i].getType(), + contents[i].getAmount(), + contents[i].getData()); + try { + for (Map.Entry entry : contents[i].getEnchantments().entrySet()) { + toAdd.addEnchantment(Enchantment.getById(entry.getKey()), entry.getValue()); + } + } catch (Throwable ignore) {} + inven.setItem(i, toAdd); + } else { + inven.setItem(i, null); + } + } + + return true; + } + + /** + * Returns whether a block has a valid ID. + * + * @param type + * @return + */ + @Override + public boolean isValidBlockType(int type) { + if (!skipNmsValidBlockCheck) { + try { + return (Boolean) nmsValidBlockMethod.invoke(null, type); + } catch (Throwable e) { + skipNmsValidBlockCheck = true; + } + } + return Material.getMaterial(type) != null && Material.getMaterial(type).isBlock(); + } + + @Override + public void checkLoadedChunk(Vector pt) { + if (!world.isChunkLoaded(pt.getBlockX() >> 4, pt.getBlockZ() >> 4)) { + world.loadChunk(pt.getBlockX() >> 4, pt.getBlockZ() >> 4); + } + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof BukkitWorld)) { + return false; + } + + return ((BukkitWorld) other).world.equals(world); + } + + @Override + public int hashCode() { + return world.hashCode(); + } + + @Override + public int getMaxY() { + return world.getMaxHeight() - 1; + } + + @Override + public void fixAfterFastMode(Iterable chunks) { + for (BlockVector2D chunkPos : chunks) { + world.refreshChunk(chunkPos.getBlockX(), chunkPos.getBlockZ()); + } + } + + private static final Map effects = new HashMap(); + static { + for (Effect effect : Effect.values()) { + effects.put(effect.getId(), effect); + } + } + + @Override + public boolean playEffect(Vector position, int type, int data) { + final Effect effect = effects.get(type); + if (effect == null) { + return false; + } + + world.playEffect(BukkitUtil.toLocation(world, position), effect, data); + + return true; + } + + @Override + public void simulateBlockMine(Vector pt) { + world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).breakNaturally(); + } + + @Override + public LocalEntity[] getEntities(Region region) { + List entities = new ArrayList(); + for (Vector2D pt : region.getChunks()) { + if (!world.isChunkLoaded(pt.getBlockX(), pt.getBlockZ())) { + continue; + } + + final Entity[] ents = world.getChunkAt(pt.getBlockX(), pt.getBlockZ()).getEntities(); + for (Entity ent : ents) { + if (region.contains(BukkitUtil.toVector(ent.getLocation()))) { + entities.add(BukkitUtil.toLocalEntity(ent)); + } + } + } + return entities.toArray(new BukkitEntity[entities.size()]); + } + + @Override + public int killEntities(LocalEntity... entities) { + int amount = 0; + Set toKill = new HashSet(); + for (LocalEntity entity : entities) { + toKill.add(((BukkitEntity) entity).getEntityId()); + } + for (Entity entity : world.getEntities()) { + if (toKill.contains(entity.getUniqueId())) { + entity.remove(); + ++amount; + } + } + return amount; + } + + @Override + public BaseBlock getBlock(Vector pt) { + int type = getBlockType(pt); + int data = getBlockData(pt); + + switch (type) { + case BlockID.WALL_SIGN: + case BlockID.SIGN_POST: + //case BlockID.CHEST: // Prevent data loss for now + //case BlockID.FURNACE: + //case BlockID.BURNING_FURNACE: + //case BlockID.DISPENSER: + //case BlockID.MOB_SPAWNER: + case BlockID.NOTE_BLOCK: + case BlockID.HEAD: + return super.getBlock(pt); + default: + if (!skipNmsAccess) { + try { + NmsBlock block = null; + block = (NmsBlock) nmsGetMethod.invoke(null, getWorld(), pt, type, data); + if (block != null) { + return block; + } + } catch (Throwable t) { + logger.log(Level.WARNING, + "WorldEdit: Failed to do NMS access for direct NBT data copy", t); + skipNmsAccess = true; + } + } + } + + return super.getBlock(pt); + } + + @SuppressWarnings("deprecation") + @Override + public BaseBlock getLazyBlock(Vector position) { + Block bukkitBlock = world.getBlockAt(position.getBlockX(), position.getBlockY(), position.getBlockZ()); + return new LazyBlock(bukkitBlock.getTypeId(), bukkitBlock.getData(), this, position); + } + + @Override + public boolean setBlock(Vector pt, BaseBlock block, boolean notifyAdjacent) { + if (!skipNmsSafeSet) { + try { + return (Boolean) nmsSetSafeMethod.invoke(null, this, pt, block, notifyAdjacent); + } catch (Throwable t) { + logger.log(Level.WARNING, "WorldEdit: Failed to do NMS safe block set", t); + skipNmsSafeSet = true; + } + } + + return super.setBlock(pt, block, notifyAdjacent); + } +} diff --git a/src/main/java/com/sk89q/worldedit/bukkit/CUIChannelListener.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/CUIChannelListener.java similarity index 100% rename from src/main/java/com/sk89q/worldedit/bukkit/CUIChannelListener.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/CUIChannelListener.java diff --git a/src/main/java/com/sk89q/worldedit/bukkit/DefaultNmsBlock.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/DefaultNmsBlock.java similarity index 97% rename from src/main/java/com/sk89q/worldedit/bukkit/DefaultNmsBlock.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/DefaultNmsBlock.java index 23fd20561..2e718757b 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/DefaultNmsBlock.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/DefaultNmsBlock.java @@ -1,436 +1,436 @@ -package com.sk89q.worldedit.bukkit; -// $Id$ -/* - * This file is a part of WorldEdit. - * Copyright (c) sk89q - * Copyright (c) the 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 - * (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 - * 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 . - */ - -import com.sk89q.jnbt.*; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.blocks.TileEntityBlock; -import com.sk89q.worldedit.data.DataException; -import com.sk89q.worldedit.foundation.Block; -import net.minecraft.server.v1_7_R2.*; -import org.bukkit.World; -import org.bukkit.craftbukkit.v1_7_R2.CraftWorld; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.*; -import java.util.logging.Logger; - -/** - * A blind handler of blocks with TileEntity data that directly access Minecraft's - * classes through CraftBukkit. - *

- * Usage of this class may break terribly in the future, and therefore usage should - * be trapped in a handler for {@link Throwable}. - */ -public class DefaultNmsBlock extends NmsBlock { - - private static final Logger logger = WorldEdit.logger; - private static Field compoundMapField; - private static final Field nmsBlock_isTileEntityField; // The field is deobfuscated but the method isn't. No idea why. - private NBTTagCompound nbtData = null; - - static { - Field field; - try { - field = net.minecraft.server.v1_7_R2.Block.class.getDeclaredField("isTileEntity"); - field.setAccessible(true); - } catch (NoSuchFieldException e) { - // logger.severe("Could not find NMS block tile entity field!"); - field = null; - } - nmsBlock_isTileEntityField = field; - } - - public static boolean verify() { - return nmsBlock_isTileEntityField != null; - } - - /** - * Create a new instance with a given type ID, data value, and previous - * {@link TileEntityBlock}-implementing object. - * - * @param type block type ID - * @param data data value - * @param tileEntityBlock tile entity block - */ - public DefaultNmsBlock(int type, int data, TileEntityBlock tileEntityBlock) { - super(type, data); - - nbtData = (NBTTagCompound) fromNative(tileEntityBlock.getNbtData()); - } - - /** - * Create a new instance with a given type ID, data value, and raw - * {@link NBTTagCompound} copy. - * - * @param type block type ID - * @param data data value - * @param nbtData raw NBT data - */ - public DefaultNmsBlock(int type, int data, NBTTagCompound nbtData) { - super(type, data); - - this.nbtData = nbtData; - } - - /** - * Build a {@link NBTTagCompound} that has valid coordinates. - * - * @param pt coordinates to set - * @return the tag compound - */ - private NBTTagCompound getNmsData(Vector pt) { - if (nbtData == null) { - return null; - } - - nbtData.set("x", new NBTTagInt(pt.getBlockX())); - nbtData.set("y", new NBTTagInt(pt.getBlockY())); - nbtData.set("z", new NBTTagInt(pt.getBlockZ())); - - return nbtData; - } - - @Override - public boolean hasNbtData() { - return nbtData != null; - } - - @Override - public String getNbtId() { - if (nbtData == null) { - return ""; - } - - return nbtData.getString("id"); - } - - @Override - public CompoundTag getNbtData() { - if (nbtData == null) { - return new CompoundTag(getNbtId(), - new HashMap()); - } - return (CompoundTag) toNative(nbtData); - } - - @Override - public void setNbtData(CompoundTag tag) throws DataException { - if (tag == null) { - this.nbtData = null; - } - this.nbtData = (NBTTagCompound) fromNative(tag); - } - - /** - * Build an instance from the given information. - * - * @param world world to get the block from - * @param position position to get the block at - * @param type type ID of block - * @param data data value of block - * @return the block, or null - */ - public static DefaultNmsBlock get(World world, Vector position, int type, int data) { - if (!hasTileEntity(type)) { - return null; - } - - TileEntity te = ((CraftWorld) world).getHandle().getTileEntity( - position.getBlockX(), position.getBlockY(), position.getBlockZ()); - - if (te != null) { - NBTTagCompound tag = new NBTTagCompound(); - te.b(tag); // Load data - return new DefaultNmsBlock(type, data, tag); - } - - return null; - } - - /** - * Set an instance or a {@link TileEntityBlock} to the given position. - * - * @param world world to set the block in - * @param position position to set the block at - * @param block the block to set - * @return true if tile entity data was copied to the world - */ - public static boolean set(World world, Vector position, BaseBlock block) { - NBTTagCompound data = null; - if (!hasTileEntity(world.getBlockTypeIdAt(position.getBlockX(), position.getBlockY(), position.getBlockZ()))) { - return false; - } - - if (block instanceof DefaultNmsBlock) { - DefaultNmsBlock nmsProxyBlock = (DefaultNmsBlock) block; - data = nmsProxyBlock.getNmsData(position); - } else if (block instanceof TileEntityBlock) { - DefaultNmsBlock nmsProxyBlock = new DefaultNmsBlock( - block.getId(), block.getData(), block); - data = nmsProxyBlock.getNmsData(position); - } - - if (data != null) { - TileEntity te = ((CraftWorld) world).getHandle().getTileEntity( - position.getBlockX(), position.getBlockY(), position.getBlockZ()); - if (te != null) { - te.a(data); // Load data - return true; - } - } - - return false; - } - - /** - * Tries to set a block 'safely', as in setting the block data to the location, and - * then triggering physics only at the end. - * - * @param world world to set the block in - * @param position position to set the block at - * @param block the block to set - * @param notifyAdjacent true to notify physics and what not - * @return true if block id or data was changed - */ - public static boolean setSafely(BukkitWorld world, Vector position, - Block block, boolean notifyAdjacent) { - - int x = position.getBlockX(); - int y = position.getBlockY(); - int z = position.getBlockZ(); - - CraftWorld craftWorld = ((CraftWorld) world.getWorld()); -// TileEntity te = craftWorld.getHandle().getTileEntity(x, y, z); -// craftWorld.getHandle().tileEntityList.remove(te); - - boolean changed = craftWorld.getHandle().setTypeAndData(x, y, z, getNmsBlock(block.getId()), block.getData(), 0); - - if (block instanceof BaseBlock) { - world.copyToWorld(position, (BaseBlock) block); - } - - changed = craftWorld.getHandle().setData(x, y, z, block.getData(), 0) || changed; - if (changed && notifyAdjacent) { - craftWorld.getHandle().notify(x, y, z); - craftWorld.getHandle().update(x, y, z, getNmsBlock(block.getId())); - } - - return changed; - } - - public static boolean hasTileEntity(int type) { - net.minecraft.server.v1_7_R2.Block nmsBlock = getNmsBlock(type); - if (nmsBlock == null) { - return false; - } - - try { - return nmsBlock_isTileEntityField.getBoolean(nmsBlock); // Once we have the field stord, gets are fast - } catch (IllegalAccessException e) { - return false; - } - } - - public static net.minecraft.server.v1_7_R2.Block getNmsBlock(int type) { - return net.minecraft.server.v1_7_R2.Block.e(type); - } - - /** - * Converts from a non-native NMS NBT structure to a native WorldEdit NBT - * structure. - * - * @param foreign non-native NMS NBT structure - * @return native WorldEdit NBT structure - */ - private static Tag toNative(NBTBase foreign) { - // temporary fix since mojang removed names from tags - // our nbt spec will need to be updated to theirs - return toNative(NBTBase.getTagName(foreign.getTypeId()), foreign); - } - - /** - * Converts from a non-native NMS NBT structure to a native WorldEdit NBT - * structure. - * - * @param foreign non-native NMS NBT structure - * @param name name for the tag, if it has one - * @return native WorldEdit NBT structure - */ - @SuppressWarnings("unchecked") - private static Tag toNative(String name, NBTBase foreign) { - if (foreign == null) { - return null; - } - if (foreign instanceof NBTTagCompound) { - Map values = new HashMap(); - Collection foreignKeys = null; - - if (compoundMapField == null) { - try { - // Method name may change! - foreignKeys = ((NBTTagCompound) foreign).c(); - } catch (Throwable t) { - try { - logger.warning("WorldEdit: Couldn't get NBTTagCompound.c(), " + - "so we're going to try to get at the 'map' field directly from now on"); - - if (compoundMapField == null) { - compoundMapField = NBTTagCompound.class.getDeclaredField("map"); - compoundMapField.setAccessible(true); - } - } catch (Throwable e) { - // Can't do much beyond this - throw new RuntimeException(e); - } - } - } - - if (compoundMapField != null) { - try { - foreignKeys = ((HashMap) compoundMapField.get(foreign)).keySet(); - } catch (Throwable e) { - // Can't do much beyond this - throw new RuntimeException(e); - } - } - - for (Object obj : foreignKeys) { - String key = (String) obj; - NBTBase base = (NBTBase) ((NBTTagCompound) foreign).get(key); - values.put(key, toNative(key, base)); - } - return new CompoundTag(name, values); - } else if (foreign instanceof NBTTagByte) { - return new ByteTag(name, ((NBTTagByte) foreign).f()); // getByte - } else if (foreign instanceof NBTTagByteArray) { - return new ByteArrayTag(name, - ((NBTTagByteArray) foreign).c()); // data - } else if (foreign instanceof NBTTagDouble) { - return new DoubleTag(name, - ((NBTTagDouble) foreign).g()); // getDouble - } else if (foreign instanceof NBTTagFloat) { - return new FloatTag(name, ((NBTTagFloat) foreign).h()); // getFloat - } else if (foreign instanceof NBTTagInt) { - return new IntTag(name, ((NBTTagInt) foreign).d()); // getInt - } else if (foreign instanceof NBTTagIntArray) { - return new IntArrayTag(name, - ((NBTTagIntArray) foreign).c()); // data - } else if (foreign instanceof NBTTagList) { - try { - return transmorgifyList(name, (NBTTagList) foreign); - } catch (NoSuchFieldException e) { - } catch (SecurityException e) { - } catch (IllegalArgumentException e) { - } catch (IllegalAccessException e) {} - return new ListTag(name, ByteTag.class, new ArrayList()); - } else if (foreign instanceof NBTTagLong) { - return new LongTag(name, ((NBTTagLong) foreign).c()); // getLong - } else if (foreign instanceof NBTTagShort) { - return new ShortTag(name, ((NBTTagShort) foreign).e()); // getShort - } else if (foreign instanceof NBTTagString) { - return new StringTag(name, - ((NBTTagString) foreign).a_()); // data - } else if (foreign instanceof NBTTagEnd) { - return new EndTag(); - } else { - throw new IllegalArgumentException("Don't know how to make native " - + foreign.getClass().getCanonicalName()); - } - } - - private static ListTag transmorgifyList(String name, NBTTagList foreign) - throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { - List values = new ArrayList(); - int type = foreign.d(); - Field listField = NBTTagList.class.getDeclaredField("list"); - listField.setAccessible(true); - List foreignList; - foreignList = (List) listField.get(foreign); - for (int i = 0; i < foreign.size(); i++) { - NBTBase element = (NBTBase) foreignList.get(i); - values.add(toNative(null, element)); // list elements shouldn't have names - } - Class cls = NBTConstants.getClassFromType(type); - return new ListTag(name, cls, values); - } - - /** - * Converts a WorldEdit-native NBT structure to a NMS structure. - * - * @param foreign structure to convert - * @return non-native structure - */ - private static NBTBase fromNative(Tag foreign) { - if (foreign == null) { - return null; - } - if (foreign instanceof CompoundTag) { - NBTTagCompound tag = new NBTTagCompound(); - for (Map.Entry entry : ((CompoundTag) foreign) - .getValue().entrySet()) { - tag.set(entry.getKey(), fromNative(entry.getValue())); - } - return tag; - } else if (foreign instanceof ByteTag) { - return new NBTTagByte(((ByteTag) foreign).getValue()); - } else if (foreign instanceof ByteArrayTag) { - return new NBTTagByteArray(((ByteArrayTag) foreign).getValue()); - } else if (foreign instanceof DoubleTag) { - return new NBTTagDouble(((DoubleTag) foreign).getValue()); - } else if (foreign instanceof FloatTag) { - return new NBTTagFloat(((FloatTag) foreign).getValue()); - } else if (foreign instanceof IntTag) { - return new NBTTagInt(((IntTag) foreign).getValue()); - } else if (foreign instanceof IntArrayTag) { - return new NBTTagIntArray(((IntArrayTag) foreign).getValue()); - } else if (foreign instanceof ListTag) { - NBTTagList tag = new NBTTagList(); - ListTag foreignList = (ListTag) foreign; - for (Tag t : foreignList.getValue()) { - tag.add(fromNative(t)); - } - return tag; - } else if (foreign instanceof LongTag) { - return new NBTTagLong(((LongTag) foreign).getValue()); - } else if (foreign instanceof ShortTag) { - return new NBTTagShort(((ShortTag) foreign).getValue()); - } else if (foreign instanceof StringTag) { - return new NBTTagString(((StringTag) foreign).getValue()); - } else if (foreign instanceof EndTag) { - try { - Method tagMaker = NBTBase.class.getDeclaredMethod("createTag", byte.class); - tagMaker.setAccessible(true); - return (NBTBase) tagMaker.invoke(null, (byte) 0); - } catch (Exception e) { - return null; - } - } else { - throw new IllegalArgumentException("Don't know how to make NMS " - + foreign.getClass().getCanonicalName()); - } - } - - public static boolean isValidBlockType(int type) throws NoClassDefFoundError { - return type == 0 || (type >= 1 && net.minecraft.server.v1_7_R2.Block.e(type) != null); - } - -} +package com.sk89q.worldedit.bukkit; +// $Id$ +/* + * This file is a part of WorldEdit. + * Copyright (c) sk89q + * Copyright (c) the 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 + * (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 + * 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 . + */ + +import com.sk89q.jnbt.*; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.TileEntityBlock; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.foundation.Block; +import net.minecraft.server.v1_7_R2.*; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_7_R2.CraftWorld; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.*; +import java.util.logging.Logger; + +/** + * A blind handler of blocks with TileEntity data that directly access Minecraft's + * classes through CraftBukkit. + *

+ * Usage of this class may break terribly in the future, and therefore usage should + * be trapped in a handler for {@link Throwable}. + */ +public class DefaultNmsBlock extends NmsBlock { + + private static final Logger logger = WorldEdit.logger; + private static Field compoundMapField; + private static final Field nmsBlock_isTileEntityField; // The field is deobfuscated but the method isn't. No idea why. + private NBTTagCompound nbtData = null; + + static { + Field field; + try { + field = net.minecraft.server.v1_7_R2.Block.class.getDeclaredField("isTileEntity"); + field.setAccessible(true); + } catch (NoSuchFieldException e) { + // logger.severe("Could not find NMS block tile entity field!"); + field = null; + } + nmsBlock_isTileEntityField = field; + } + + public static boolean verify() { + return nmsBlock_isTileEntityField != null; + } + + /** + * Create a new instance with a given type ID, data value, and previous + * {@link TileEntityBlock}-implementing object. + * + * @param type block type ID + * @param data data value + * @param tileEntityBlock tile entity block + */ + public DefaultNmsBlock(int type, int data, TileEntityBlock tileEntityBlock) { + super(type, data); + + nbtData = (NBTTagCompound) fromNative(tileEntityBlock.getNbtData()); + } + + /** + * Create a new instance with a given type ID, data value, and raw + * {@link NBTTagCompound} copy. + * + * @param type block type ID + * @param data data value + * @param nbtData raw NBT data + */ + public DefaultNmsBlock(int type, int data, NBTTagCompound nbtData) { + super(type, data); + + this.nbtData = nbtData; + } + + /** + * Build a {@link NBTTagCompound} that has valid coordinates. + * + * @param pt coordinates to set + * @return the tag compound + */ + private NBTTagCompound getNmsData(Vector pt) { + if (nbtData == null) { + return null; + } + + nbtData.set("x", new NBTTagInt(pt.getBlockX())); + nbtData.set("y", new NBTTagInt(pt.getBlockY())); + nbtData.set("z", new NBTTagInt(pt.getBlockZ())); + + return nbtData; + } + + @Override + public boolean hasNbtData() { + return nbtData != null; + } + + @Override + public String getNbtId() { + if (nbtData == null) { + return ""; + } + + return nbtData.getString("id"); + } + + @Override + public CompoundTag getNbtData() { + if (nbtData == null) { + return new CompoundTag(getNbtId(), + new HashMap()); + } + return (CompoundTag) toNative(nbtData); + } + + @Override + public void setNbtData(CompoundTag tag) throws DataException { + if (tag == null) { + this.nbtData = null; + } + this.nbtData = (NBTTagCompound) fromNative(tag); + } + + /** + * Build an instance from the given information. + * + * @param world world to get the block from + * @param position position to get the block at + * @param type type ID of block + * @param data data value of block + * @return the block, or null + */ + public static DefaultNmsBlock get(World world, Vector position, int type, int data) { + if (!hasTileEntity(type)) { + return null; + } + + TileEntity te = ((CraftWorld) world).getHandle().getTileEntity( + position.getBlockX(), position.getBlockY(), position.getBlockZ()); + + if (te != null) { + NBTTagCompound tag = new NBTTagCompound(); + te.b(tag); // Load data + return new DefaultNmsBlock(type, data, tag); + } + + return null; + } + + /** + * Set an instance or a {@link TileEntityBlock} to the given position. + * + * @param world world to set the block in + * @param position position to set the block at + * @param block the block to set + * @return true if tile entity data was copied to the world + */ + public static boolean set(World world, Vector position, BaseBlock block) { + NBTTagCompound data = null; + if (!hasTileEntity(world.getBlockTypeIdAt(position.getBlockX(), position.getBlockY(), position.getBlockZ()))) { + return false; + } + + if (block instanceof DefaultNmsBlock) { + DefaultNmsBlock nmsProxyBlock = (DefaultNmsBlock) block; + data = nmsProxyBlock.getNmsData(position); + } else if (block instanceof TileEntityBlock) { + DefaultNmsBlock nmsProxyBlock = new DefaultNmsBlock( + block.getId(), block.getData(), block); + data = nmsProxyBlock.getNmsData(position); + } + + if (data != null) { + TileEntity te = ((CraftWorld) world).getHandle().getTileEntity( + position.getBlockX(), position.getBlockY(), position.getBlockZ()); + if (te != null) { + te.a(data); // Load data + return true; + } + } + + return false; + } + + /** + * Tries to set a block 'safely', as in setting the block data to the location, and + * then triggering physics only at the end. + * + * @param world world to set the block in + * @param position position to set the block at + * @param block the block to set + * @param notifyAdjacent true to notify physics and what not + * @return true if block id or data was changed + */ + public static boolean setSafely(BukkitWorld world, Vector position, + Block block, boolean notifyAdjacent) { + + int x = position.getBlockX(); + int y = position.getBlockY(); + int z = position.getBlockZ(); + + CraftWorld craftWorld = ((CraftWorld) world.getWorld()); +// TileEntity te = craftWorld.getHandle().getTileEntity(x, y, z); +// craftWorld.getHandle().tileEntityList.remove(te); + + boolean changed = craftWorld.getHandle().setTypeAndData(x, y, z, getNmsBlock(block.getId()), block.getData(), 0); + + if (block instanceof BaseBlock) { + world.copyToWorld(position, (BaseBlock) block); + } + + changed = craftWorld.getHandle().setData(x, y, z, block.getData(), 0) || changed; + if (changed && notifyAdjacent) { + craftWorld.getHandle().notify(x, y, z); + craftWorld.getHandle().update(x, y, z, getNmsBlock(block.getId())); + } + + return changed; + } + + public static boolean hasTileEntity(int type) { + net.minecraft.server.v1_7_R2.Block nmsBlock = getNmsBlock(type); + if (nmsBlock == null) { + return false; + } + + try { + return nmsBlock_isTileEntityField.getBoolean(nmsBlock); // Once we have the field stord, gets are fast + } catch (IllegalAccessException e) { + return false; + } + } + + public static net.minecraft.server.v1_7_R2.Block getNmsBlock(int type) { + return net.minecraft.server.v1_7_R2.Block.e(type); + } + + /** + * Converts from a non-native NMS NBT structure to a native WorldEdit NBT + * structure. + * + * @param foreign non-native NMS NBT structure + * @return native WorldEdit NBT structure + */ + private static Tag toNative(NBTBase foreign) { + // temporary fix since mojang removed names from tags + // our nbt spec will need to be updated to theirs + return toNative(NBTBase.getTagName(foreign.getTypeId()), foreign); + } + + /** + * Converts from a non-native NMS NBT structure to a native WorldEdit NBT + * structure. + * + * @param foreign non-native NMS NBT structure + * @param name name for the tag, if it has one + * @return native WorldEdit NBT structure + */ + @SuppressWarnings("unchecked") + private static Tag toNative(String name, NBTBase foreign) { + if (foreign == null) { + return null; + } + if (foreign instanceof NBTTagCompound) { + Map values = new HashMap(); + Collection foreignKeys = null; + + if (compoundMapField == null) { + try { + // Method name may change! + foreignKeys = ((NBTTagCompound) foreign).c(); + } catch (Throwable t) { + try { + logger.warning("WorldEdit: Couldn't get NBTTagCompound.c(), " + + "so we're going to try to get at the 'map' field directly from now on"); + + if (compoundMapField == null) { + compoundMapField = NBTTagCompound.class.getDeclaredField("map"); + compoundMapField.setAccessible(true); + } + } catch (Throwable e) { + // Can't do much beyond this + throw new RuntimeException(e); + } + } + } + + if (compoundMapField != null) { + try { + foreignKeys = ((HashMap) compoundMapField.get(foreign)).keySet(); + } catch (Throwable e) { + // Can't do much beyond this + throw new RuntimeException(e); + } + } + + for (Object obj : foreignKeys) { + String key = (String) obj; + NBTBase base = (NBTBase) ((NBTTagCompound) foreign).get(key); + values.put(key, toNative(key, base)); + } + return new CompoundTag(name, values); + } else if (foreign instanceof NBTTagByte) { + return new ByteTag(name, ((NBTTagByte) foreign).f()); // getByte + } else if (foreign instanceof NBTTagByteArray) { + return new ByteArrayTag(name, + ((NBTTagByteArray) foreign).c()); // data + } else if (foreign instanceof NBTTagDouble) { + return new DoubleTag(name, + ((NBTTagDouble) foreign).g()); // getDouble + } else if (foreign instanceof NBTTagFloat) { + return new FloatTag(name, ((NBTTagFloat) foreign).h()); // getFloat + } else if (foreign instanceof NBTTagInt) { + return new IntTag(name, ((NBTTagInt) foreign).d()); // getInt + } else if (foreign instanceof NBTTagIntArray) { + return new IntArrayTag(name, + ((NBTTagIntArray) foreign).c()); // data + } else if (foreign instanceof NBTTagList) { + try { + return transmorgifyList(name, (NBTTagList) foreign); + } catch (NoSuchFieldException e) { + } catch (SecurityException e) { + } catch (IllegalArgumentException e) { + } catch (IllegalAccessException e) {} + return new ListTag(name, ByteTag.class, new ArrayList()); + } else if (foreign instanceof NBTTagLong) { + return new LongTag(name, ((NBTTagLong) foreign).c()); // getLong + } else if (foreign instanceof NBTTagShort) { + return new ShortTag(name, ((NBTTagShort) foreign).e()); // getShort + } else if (foreign instanceof NBTTagString) { + return new StringTag(name, + ((NBTTagString) foreign).a_()); // data + } else if (foreign instanceof NBTTagEnd) { + return new EndTag(); + } else { + throw new IllegalArgumentException("Don't know how to make native " + + foreign.getClass().getCanonicalName()); + } + } + + private static ListTag transmorgifyList(String name, NBTTagList foreign) + throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + List values = new ArrayList(); + int type = foreign.d(); + Field listField = NBTTagList.class.getDeclaredField("list"); + listField.setAccessible(true); + List foreignList; + foreignList = (List) listField.get(foreign); + for (int i = 0; i < foreign.size(); i++) { + NBTBase element = (NBTBase) foreignList.get(i); + values.add(toNative(null, element)); // list elements shouldn't have names + } + Class cls = NBTConstants.getClassFromType(type); + return new ListTag(name, cls, values); + } + + /** + * Converts a WorldEdit-native NBT structure to a NMS structure. + * + * @param foreign structure to convert + * @return non-native structure + */ + private static NBTBase fromNative(Tag foreign) { + if (foreign == null) { + return null; + } + if (foreign instanceof CompoundTag) { + NBTTagCompound tag = new NBTTagCompound(); + for (Map.Entry entry : ((CompoundTag) foreign) + .getValue().entrySet()) { + tag.set(entry.getKey(), fromNative(entry.getValue())); + } + return tag; + } else if (foreign instanceof ByteTag) { + return new NBTTagByte(((ByteTag) foreign).getValue()); + } else if (foreign instanceof ByteArrayTag) { + return new NBTTagByteArray(((ByteArrayTag) foreign).getValue()); + } else if (foreign instanceof DoubleTag) { + return new NBTTagDouble(((DoubleTag) foreign).getValue()); + } else if (foreign instanceof FloatTag) { + return new NBTTagFloat(((FloatTag) foreign).getValue()); + } else if (foreign instanceof IntTag) { + return new NBTTagInt(((IntTag) foreign).getValue()); + } else if (foreign instanceof IntArrayTag) { + return new NBTTagIntArray(((IntArrayTag) foreign).getValue()); + } else if (foreign instanceof ListTag) { + NBTTagList tag = new NBTTagList(); + ListTag foreignList = (ListTag) foreign; + for (Tag t : foreignList.getValue()) { + tag.add(fromNative(t)); + } + return tag; + } else if (foreign instanceof LongTag) { + return new NBTTagLong(((LongTag) foreign).getValue()); + } else if (foreign instanceof ShortTag) { + return new NBTTagShort(((ShortTag) foreign).getValue()); + } else if (foreign instanceof StringTag) { + return new NBTTagString(((StringTag) foreign).getValue()); + } else if (foreign instanceof EndTag) { + try { + Method tagMaker = NBTBase.class.getDeclaredMethod("createTag", byte.class); + tagMaker.setAccessible(true); + return (NBTBase) tagMaker.invoke(null, (byte) 0); + } catch (Exception e) { + return null; + } + } else { + throw new IllegalArgumentException("Don't know how to make NMS " + + foreign.getClass().getCanonicalName()); + } + } + + public static boolean isValidBlockType(int type) throws NoClassDefFoundError { + return type == 0 || (type >= 1 && net.minecraft.server.v1_7_R2.Block.e(type) != null); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/bukkit/EditSessionBlockChangeDelegate.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/EditSessionBlockChangeDelegate.java similarity index 97% rename from src/main/java/com/sk89q/worldedit/bukkit/EditSessionBlockChangeDelegate.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/EditSessionBlockChangeDelegate.java index 2a8bae6c4..7d6d6d457 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/EditSessionBlockChangeDelegate.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/EditSessionBlockChangeDelegate.java @@ -1,76 +1,76 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.bukkit; - -import com.sk89q.worldedit.blocks.BlockID; -import org.bukkit.BlockChangeDelegate; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.blocks.BaseBlock; - -/** - * Proxy class to catch calls to set blocks. - * - * @author sk89q - */ -public class EditSessionBlockChangeDelegate implements BlockChangeDelegate { - private EditSession editSession; - - public EditSessionBlockChangeDelegate(EditSession editSession) { - this.editSession = editSession; - } - - public boolean setRawTypeId(int x, int y, int z, int typeId) { - try { - return editSession.setBlock(new Vector(x, y, z), new BaseBlock(typeId)); - } catch (MaxChangedBlocksException ex) { - return false; - } - } - - public boolean setRawTypeIdAndData(int x, int y, int z, int typeId, int data) { - try { - return editSession.setBlock(new Vector(x, y, z), new BaseBlock(typeId, data)); - } catch (MaxChangedBlocksException ex) { - return false; - } - } - - public boolean setTypeId(int x, int y, int z, int typeId) { - return setRawTypeId(x, y, z, typeId); - } - - public boolean setTypeIdAndData(int x, int y, int z, int typeId, int data) { - return setRawTypeIdAndData(x, y, z, typeId, data); - } - - public int getTypeId(int x, int y, int z) { - return editSession.getBlockType(new Vector(x, y, z)); - } - - public int getHeight() { - return editSession.getWorld().getMaxY() + 1; - } - - public boolean isEmpty(int x, int y, int z) { - return editSession.getBlockType(new Vector(x, y, z)) == BlockID.AIR; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.bukkit; + +import com.sk89q.worldedit.blocks.BlockID; +import org.bukkit.BlockChangeDelegate; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.blocks.BaseBlock; + +/** + * Proxy class to catch calls to set blocks. + * + * @author sk89q + */ +public class EditSessionBlockChangeDelegate implements BlockChangeDelegate { + private EditSession editSession; + + public EditSessionBlockChangeDelegate(EditSession editSession) { + this.editSession = editSession; + } + + public boolean setRawTypeId(int x, int y, int z, int typeId) { + try { + return editSession.setBlock(new Vector(x, y, z), new BaseBlock(typeId)); + } catch (MaxChangedBlocksException ex) { + return false; + } + } + + public boolean setRawTypeIdAndData(int x, int y, int z, int typeId, int data) { + try { + return editSession.setBlock(new Vector(x, y, z), new BaseBlock(typeId, data)); + } catch (MaxChangedBlocksException ex) { + return false; + } + } + + public boolean setTypeId(int x, int y, int z, int typeId) { + return setRawTypeId(x, y, z, typeId); + } + + public boolean setTypeIdAndData(int x, int y, int z, int typeId, int data) { + return setRawTypeIdAndData(x, y, z, typeId, data); + } + + public int getTypeId(int x, int y, int z) { + return editSession.getBlockType(new Vector(x, y, z)); + } + + public int getHeight() { + return editSession.getWorld().getMaxY() + 1; + } + + public boolean isEmpty(int x, int y, int z) { + return editSession.getBlockType(new Vector(x, y, z)) == BlockID.AIR; + } +} diff --git a/src/main/java/com/sk89q/worldedit/bukkit/NmsBlock.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/NmsBlock.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/bukkit/NmsBlock.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/NmsBlock.java index 46bd635b0..8ee32c4d0 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/NmsBlock.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/NmsBlock.java @@ -1,42 +1,42 @@ -package com.sk89q.worldedit.bukkit; - -import org.bukkit.World; - -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.foundation.Block; - -public abstract class NmsBlock extends BaseBlock { - - protected NmsBlock(int type) { - super(type); - } - - protected NmsBlock(int type, int data) { - super(type, data); - } - - public static boolean verify() { - return false; - } - - public static NmsBlock get(World world, Vector vector, int type, int data) { - return null; - } - - public static boolean set(World world, Vector vector, Block block) { - return false; - } - - public static boolean setSafely(World world, Vector vector, Block block, boolean notify) { - return false; - } - - public static boolean hasTileEntity(int type) { - return false; - } - - public static boolean isValidBlockType(int type) { - return false; - } +package com.sk89q.worldedit.bukkit; + +import org.bukkit.World; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.foundation.Block; + +public abstract class NmsBlock extends BaseBlock { + + protected NmsBlock(int type) { + super(type); + } + + protected NmsBlock(int type, int data) { + super(type, data); + } + + public static boolean verify() { + return false; + } + + public static NmsBlock get(World world, Vector vector, int type, int data) { + return null; + } + + public static boolean set(World world, Vector vector, Block block) { + return false; + } + + public static boolean setSafely(World world, Vector vector, Block block, boolean notify) { + return false; + } + + public static boolean hasTileEntity(int type) { + return false; + } + + public static boolean isValidBlockType(int type) { + return false; + } } \ No newline at end of file diff --git a/src/main/java/com/sk89q/worldedit/bukkit/SessionTimer.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/SessionTimer.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/bukkit/SessionTimer.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/SessionTimer.java index 6932af4b3..b2add99d6 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/SessionTimer.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/SessionTimer.java @@ -1,51 +1,51 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.bukkit; - -import org.bukkit.Server; -import org.bukkit.entity.Player; -import com.sk89q.worldedit.SessionCheck; -import com.sk89q.worldedit.WorldEdit; - -/** - * Used to remove expired sessions in Bukkit. - * - * @author sk89q - */ -public class SessionTimer implements Runnable { - - private WorldEdit worldEdit; - private SessionCheck checker; - - public SessionTimer(WorldEdit worldEdit, final Server server) { - this.worldEdit = worldEdit; - this.checker = new SessionCheck() { - public boolean isOnlinePlayer(String name) { - Player player = server.getPlayer(name); - return player != null && player.isOnline(); - } - }; - } - - public void run() { - worldEdit.flushExpiredSessions(checker); - } - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.bukkit; + +import org.bukkit.Server; +import org.bukkit.entity.Player; +import com.sk89q.worldedit.SessionCheck; +import com.sk89q.worldedit.WorldEdit; + +/** + * Used to remove expired sessions in Bukkit. + * + * @author sk89q + */ +public class SessionTimer implements Runnable { + + private WorldEdit worldEdit; + private SessionCheck checker; + + public SessionTimer(WorldEdit worldEdit, final Server server) { + this.worldEdit = worldEdit; + this.checker = new SessionCheck() { + public boolean isOnlinePlayer(String name) { + Player player = server.getPlayer(name); + return player != null && player.isOnline(); + } + }; + } + + public void run() { + worldEdit.flushExpiredSessions(checker); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/bukkit/WorldEditAPI.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/WorldEditAPI.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/bukkit/WorldEditAPI.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/WorldEditAPI.java index d85f49457..c302ff31a 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/WorldEditAPI.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/WorldEditAPI.java @@ -1,42 +1,42 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.bukkit; - -import org.bukkit.entity.Player; -import com.sk89q.worldedit.LocalSession; - -public class WorldEditAPI { - private WorldEditPlugin plugin; - - public WorldEditAPI(WorldEditPlugin plugin) { - this.plugin = plugin; - } - - /** - * Get the session for a player. - * - * @param player - * @return - */ - public LocalSession getSession(Player player) { - return plugin.getWorldEdit().getSession( - new BukkitPlayer(plugin, plugin.getServerInterface(), player)); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.bukkit; + +import org.bukkit.entity.Player; +import com.sk89q.worldedit.LocalSession; + +public class WorldEditAPI { + private WorldEditPlugin plugin; + + public WorldEditAPI(WorldEditPlugin plugin) { + this.plugin = plugin; + } + + /** + * Get the session for a player. + * + * @param player + * @return + */ + public LocalSession getSession(Player player) { + return plugin.getWorldEdit().getSession( + new BukkitPlayer(plugin, plugin.getServerInterface(), player)); + } +} diff --git a/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/WorldEditListener.java similarity index 97% rename from src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/WorldEditListener.java index 4b1dccb8a..590cc0c31 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/WorldEditListener.java @@ -1,178 +1,178 @@ -/* - * WorldEdit - * Copyright (C) 2012 sk89q - * - * 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 . - */ - -// $Id$ - -package com.sk89q.worldedit.bukkit; - -import org.bukkit.Bukkit; -import org.bukkit.block.Block; -import org.bukkit.event.Event.Result; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; -import org.bukkit.event.player.PlayerCommandPreprocessEvent; -import org.bukkit.event.player.PlayerGameModeChangeEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.player.PlayerQuitEvent; - -import com.sk89q.util.StringUtil; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalWorld; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.WorldVector; - -/** - * Handles all events thrown in relation to a Player - */ -public class WorldEditListener implements Listener { - - private WorldEditPlugin plugin; - private boolean ignoreLeftClickAir = false; - - /** - * Called when a player plays an animation, such as an arm swing - * - * @param event Relevant event details - */ - - /** - * Construct the object; - * - * @param plugin - */ - public WorldEditListener(WorldEditPlugin plugin) { - this.plugin = plugin; - } - - /** - * Called when a player leaves a server - * - * @param event Relevant event details - */ - @EventHandler - public void onPlayerQuit(PlayerQuitEvent event) { - plugin.getWorldEdit().markExpire(plugin.wrapPlayer(event.getPlayer())); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onGamemode(PlayerGameModeChangeEvent event) { - // this will automatically refresh their sesssion, we don't have to do anything - WorldEdit.getInstance().getSession(plugin.wrapPlayer(event.getPlayer())); - } - - /** - * Called when a player attempts to use a command - * - * @param event Relevant event details - */ - @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) - public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { - String[] split = event.getMessage().split(" "); - - if (split.length > 0) { - split = plugin.getWorldEdit().commandDetection(split); - split[0] = "/" + split[0]; - } - - final String newMessage = StringUtil.joinString(split, " "); - - if (!newMessage.equals(event.getMessage())) { - event.setMessage(newMessage); - plugin.getServer().getPluginManager().callEvent(event); - if (!event.isCancelled()) { - if (event.getMessage().length() > 0) { - plugin.getServer().dispatchCommand(event.getPlayer(), - event.getMessage().substring(1)); - } - event.setCancelled(true); - } - } - } - - /** - * Called when a player interacts - * - * @param event Relevant event details - */ - @EventHandler - public void onPlayerInteract(PlayerInteractEvent event) { - if (event.useItemInHand() == Result.DENY) { - return; - } - - final LocalPlayer player = plugin.wrapPlayer(event.getPlayer()); - final LocalWorld world = player.getWorld(); - final WorldEdit we = plugin.getWorldEdit(); - - Action action = event.getAction(); - if (action == Action.LEFT_CLICK_BLOCK) { - final Block clickedBlock = event.getClickedBlock(); - final WorldVector pos = new WorldVector(world, clickedBlock.getX(), - clickedBlock.getY(), clickedBlock.getZ()); - - if (we.handleBlockLeftClick(player, pos)) { - event.setCancelled(true); - } - - if (we.handleArmSwing(player)) { - event.setCancelled(true); - } - - if (!ignoreLeftClickAir) { - final int taskId = Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() { - @Override - public void run() { - ignoreLeftClickAir = false; - } - }, 2); - - if (taskId != -1) { - ignoreLeftClickAir = true; - } - } - } else if (action == Action.LEFT_CLICK_AIR) { - if (ignoreLeftClickAir) { - return; - } - - if (we.handleArmSwing(player)) { - event.setCancelled(true); - } - - - } else if (action == Action.RIGHT_CLICK_BLOCK) { - final Block clickedBlock = event.getClickedBlock(); - final WorldVector pos = new WorldVector(world, clickedBlock.getX(), - clickedBlock.getY(), clickedBlock.getZ()); - - if (we.handleBlockRightClick(player, pos)) { - event.setCancelled(true); - } - - if (we.handleRightClick(player)) { - event.setCancelled(true); - } - } else if (action == Action.RIGHT_CLICK_AIR) { - if (we.handleRightClick(player)) { - event.setCancelled(true); - } - } - } -} +/* + * WorldEdit + * Copyright (C) 2012 sk89q + * + * 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 . + */ + +// $Id$ + +package com.sk89q.worldedit.bukkit; + +import org.bukkit.Bukkit; +import org.bukkit.block.Block; +import org.bukkit.event.Event.Result; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.player.PlayerGameModeChangeEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +import com.sk89q.util.StringUtil; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldVector; + +/** + * Handles all events thrown in relation to a Player + */ +public class WorldEditListener implements Listener { + + private WorldEditPlugin plugin; + private boolean ignoreLeftClickAir = false; + + /** + * Called when a player plays an animation, such as an arm swing + * + * @param event Relevant event details + */ + + /** + * Construct the object; + * + * @param plugin + */ + public WorldEditListener(WorldEditPlugin plugin) { + this.plugin = plugin; + } + + /** + * Called when a player leaves a server + * + * @param event Relevant event details + */ + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + plugin.getWorldEdit().markExpire(plugin.wrapPlayer(event.getPlayer())); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onGamemode(PlayerGameModeChangeEvent event) { + // this will automatically refresh their sesssion, we don't have to do anything + WorldEdit.getInstance().getSession(plugin.wrapPlayer(event.getPlayer())); + } + + /** + * Called when a player attempts to use a command + * + * @param event Relevant event details + */ + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { + String[] split = event.getMessage().split(" "); + + if (split.length > 0) { + split = plugin.getWorldEdit().commandDetection(split); + split[0] = "/" + split[0]; + } + + final String newMessage = StringUtil.joinString(split, " "); + + if (!newMessage.equals(event.getMessage())) { + event.setMessage(newMessage); + plugin.getServer().getPluginManager().callEvent(event); + if (!event.isCancelled()) { + if (event.getMessage().length() > 0) { + plugin.getServer().dispatchCommand(event.getPlayer(), + event.getMessage().substring(1)); + } + event.setCancelled(true); + } + } + } + + /** + * Called when a player interacts + * + * @param event Relevant event details + */ + @EventHandler + public void onPlayerInteract(PlayerInteractEvent event) { + if (event.useItemInHand() == Result.DENY) { + return; + } + + final LocalPlayer player = plugin.wrapPlayer(event.getPlayer()); + final LocalWorld world = player.getWorld(); + final WorldEdit we = plugin.getWorldEdit(); + + Action action = event.getAction(); + if (action == Action.LEFT_CLICK_BLOCK) { + final Block clickedBlock = event.getClickedBlock(); + final WorldVector pos = new WorldVector(world, clickedBlock.getX(), + clickedBlock.getY(), clickedBlock.getZ()); + + if (we.handleBlockLeftClick(player, pos)) { + event.setCancelled(true); + } + + if (we.handleArmSwing(player)) { + event.setCancelled(true); + } + + if (!ignoreLeftClickAir) { + final int taskId = Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() { + @Override + public void run() { + ignoreLeftClickAir = false; + } + }, 2); + + if (taskId != -1) { + ignoreLeftClickAir = true; + } + } + } else if (action == Action.LEFT_CLICK_AIR) { + if (ignoreLeftClickAir) { + return; + } + + if (we.handleArmSwing(player)) { + event.setCancelled(true); + } + + + } else if (action == Action.RIGHT_CLICK_BLOCK) { + final Block clickedBlock = event.getClickedBlock(); + final WorldVector pos = new WorldVector(world, clickedBlock.getX(), + clickedBlock.getY(), clickedBlock.getZ()); + + if (we.handleBlockRightClick(player, pos)) { + event.setCancelled(true); + } + + if (we.handleRightClick(player)) { + event.setCancelled(true); + } + } else if (action == Action.RIGHT_CLICK_AIR) { + if (we.handleRightClick(player)) { + event.setCancelled(true); + } + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java similarity index 92% rename from src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java index eaba0e2af..7e40652f1 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java @@ -1,430 +1,419 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.bukkit; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Enumeration; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import java.util.logging.Handler; -import java.util.zip.ZipEntry; - -import org.bukkit.Bukkit; -import org.bukkit.World; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.plugin.java.JavaPlugin; - -import com.sk89q.util.yaml.YAMLProcessor; -import com.sk89q.wepif.PermissionsResolverManager; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.IncompleteRegionException; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.ServerInterface; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.WorldEditOperation; -import com.sk89q.worldedit.bags.BlockBag; -import com.sk89q.worldedit.bukkit.selections.CuboidSelection; -import com.sk89q.worldedit.bukkit.selections.Polygonal2DSelection; -import com.sk89q.worldedit.bukkit.selections.Selection; -import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.regions.Polygonal2DRegion; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.regions.RegionSelector; - -/** - * Plugin for Bukkit. - * - * @author sk89q - */ -public class WorldEditPlugin extends JavaPlugin { - - /** - * The name of the CUI's plugin channel registration - */ - public static final String CUI_PLUGIN_CHANNEL = "WECUI"; - - /** - * The server interface that all server-related API goes through. - */ - private BukkitServerInterface server; - /** - * Main WorldEdit instance. - */ - private WorldEdit controller; - /** - * Deprecated API. - */ - private WorldEditAPI api; - - /** - * Holds the configuration for WorldEdit. - */ - private BukkitConfiguration config; - - /** - * Called on plugin enable. - */ - @Override - public void onEnable() { - final String pluginYmlVersion = getDescription().getVersion(); - final String manifestVersion = WorldEdit.getVersion(); - - if (!manifestVersion.equalsIgnoreCase(pluginYmlVersion)) { - WorldEdit.setVersion(manifestVersion + " (" + pluginYmlVersion + ")"); - } - - // Make the data folders that WorldEdit uses - getDataFolder().mkdirs(); - File targetDir = new File(getDataFolder() + File.separator + "nmsblocks"); - targetDir.mkdir(); - copyNmsBlockClasses(targetDir); - - // Create the default configuration file - createDefaultConfiguration("config.yml"); - - // Set up configuration and such, including the permissions - // resolver - config = new BukkitConfiguration(new YAMLProcessor(new File(getDataFolder(), "config.yml"), true), this); - PermissionsResolverManager.initialize(this); - - // Load the configuration - config.load(); - - // Setup interfaces - server = new BukkitServerInterface(this, getServer()); - controller = new WorldEdit(server, config); - WorldEdit.logger.setParent(Bukkit.getLogger()); - api = new WorldEditAPI(this); - getServer().getMessenger().registerIncomingPluginChannel(this, CUI_PLUGIN_CHANNEL, new CUIChannelListener(this)); - getServer().getMessenger().registerOutgoingPluginChannel(this, CUI_PLUGIN_CHANNEL); - // Now we can register events! - getServer().getPluginManager().registerEvents(new WorldEditListener(this), this); - - getServer().getScheduler().runTaskTimerAsynchronously(this, - new SessionTimer(controller, getServer()), 120, 120); - } - - private void copyNmsBlockClasses(File target) { - try { - JarFile jar = new JarFile(getFile()); - @SuppressWarnings("rawtypes") - Enumeration entries = jar.entries(); - while (entries.hasMoreElements()) { - JarEntry jarEntry = (JarEntry) entries.nextElement(); - if (!jarEntry.getName().startsWith("nmsblocks") || jarEntry.isDirectory()) continue; - - File file = new File(target + File.separator + jarEntry.getName().replace("nmsblocks", "")); - if (file.exists()) continue; - - InputStream is = jar.getInputStream(jarEntry); - FileOutputStream fos = new FileOutputStream(file); - - fos = new FileOutputStream(file); - byte[] buf = new byte[8192]; - int length = 0; - while ((length = is.read(buf)) > 0) { - fos.write(buf, 0, length); - } - fos.close(); - is.close(); - } - } catch (Throwable e) {} - } - - /** - * Called on plugin disable. - */ - @Override - public void onDisable() { - controller.clearSessions(); - for (Handler h : controller.commandLogger.getHandlers()) { - h.close(); - } - config.unload(); - server.unregisterCommands(); - this.getServer().getScheduler().cancelTasks(this); - } - - /** - * Loads and reloads all configuration. - */ - protected void loadConfiguration() { - config.unload(); - config.load(); - getPermissionsResolver().load(); - } - - /** - * Create a default configuration file from the .jar. - * - * @param name - */ - protected void createDefaultConfiguration(String name) { - File actual = new File(getDataFolder(), name); - if (!actual.exists()) { - InputStream input = - null; - try { - JarFile file = new JarFile(getFile()); - ZipEntry copy = file.getEntry("defaults/" + name); - if (copy == null) throw new FileNotFoundException(); - input = file.getInputStream(copy); - } catch (IOException e) { - getLogger().severe("Unable to read default configuration: " + name); - } - if (input != null) { - FileOutputStream output = null; - - try { - output = new FileOutputStream(actual); - byte[] buf = new byte[8192]; - int length = 0; - while ((length = input.read(buf)) > 0) { - output.write(buf, 0, length); - } - - getLogger().info("Default configuration file written: " + name); - } catch (IOException e) { - e.printStackTrace(); - } finally { - try { - if (input != null) { - input.close(); - } - } catch (IOException e) {} - - try { - if (output != null) { - output.close(); - } - } catch (IOException e) {} - } - } - } - } - - /** - * Called on WorldEdit command. - */ - @Override - public boolean onCommand(CommandSender sender, org.bukkit.command.Command cmd, - String commandLabel, String[] args) { - - // Add the command to the array because the underlying command handling - // code of WorldEdit expects it - String[] split = new String[args.length + 1]; - System.arraycopy(args, 0, split, 1, args.length); - split[0] = "/" + cmd.getName(); - - controller.handleCommand(wrapCommandSender(sender), split); - - return true; - } - - /** - * Gets the session for the player. - * - * @param player - * @return - */ - public LocalSession getSession(Player player) { - return controller.getSession(wrapPlayer(player)); - } - - /** - * Gets the session for the player. - * - * @param player - * @return - */ - public EditSession createEditSession(Player player) { - LocalPlayer wePlayer = wrapPlayer(player); - LocalSession session = controller.getSession(wePlayer); - BlockBag blockBag = session.getBlockBag(wePlayer); - - EditSession editSession = controller.getEditSessionFactory() - .getEditSession(wePlayer.getWorld(), session.getBlockChangeLimit(), blockBag, wePlayer); - editSession.enableQueue(); - - return editSession; - } - - /** - * Remember an edit session. - * - * @param player - * @param editSession - */ - public void remember(Player player, EditSession editSession) { - LocalPlayer wePlayer = wrapPlayer(player); - LocalSession session = controller.getSession(wePlayer); - - session.remember(editSession); - editSession.flushQueue(); - - controller.flushBlockBag(wePlayer, editSession); - } - - /** - * Wrap an operation into an EditSession. - * - * @param player - * @param op - * @throws Throwable - */ - public void perform(Player player, WorldEditOperation op) - throws Throwable { - LocalPlayer wePlayer = wrapPlayer(player); - LocalSession session = controller.getSession(wePlayer); - - EditSession editSession = createEditSession(player); - try { - op.run(session, wePlayer, editSession); - } finally { - remember(player, editSession); - } - } - - /** - * Get the API. - * - * @return - */ - @Deprecated - public WorldEditAPI getAPI() { - return api; - } - - /** - * Returns the configuration used by WorldEdit. - * - * @return - */ - public BukkitConfiguration getLocalConfiguration() { - return config; - } - - /** - * Get the permissions resolver in use. - * - * @return - */ - public PermissionsResolverManager getPermissionsResolver() { - return PermissionsResolverManager.getInstance(); - } - - /** - * Used to wrap a Bukkit Player as a LocalPlayer. - * - * @param player - * @return - */ - public BukkitPlayer wrapPlayer(Player player) { - return new BukkitPlayer(this, this.server, player); - } - - public LocalPlayer wrapCommandSender(CommandSender sender) { - if (sender instanceof Player) { - return wrapPlayer((Player) sender); - } - - return new BukkitCommandSender(this, this.server, sender); - } - - /** - * Get the server interface. - * - * @return - */ - public ServerInterface getServerInterface() { - return server; - } - - /** - * Get WorldEdit. - * - * @return - */ - public WorldEdit getWorldEdit() { - return controller; - } - - /** - * Gets the region selection for the player. - * - * @param player - * @return the selection or null if there was none - */ - public Selection getSelection(Player player) { - if (player == null) { - throw new IllegalArgumentException("Null player not allowed"); - } - if (!player.isOnline()) { - throw new IllegalArgumentException("Offline player not allowed"); - } - - LocalSession session = controller.getSession(wrapPlayer(player)); - RegionSelector selector = session.getRegionSelector(BukkitUtil.getLocalWorld(player.getWorld())); - - try { - Region region = selector.getRegion(); - World world = ((BukkitWorld) session.getSelectionWorld()).getWorld(); - - if (region instanceof CuboidRegion) { - return new CuboidSelection(world, selector, (CuboidRegion) region); - } else if (region instanceof Polygonal2DRegion) { - return new Polygonal2DSelection(world, selector, (Polygonal2DRegion) region); - } else { - return null; - } - } catch (IncompleteRegionException e) { - return null; - } - } - - /** - * Sets the region selection for a player. - * - * @param player - * @param selection - */ - public void setSelection(Player player, Selection selection) { - if (player == null) { - throw new IllegalArgumentException("Null player not allowed"); - } - if (!player.isOnline()) { - throw new IllegalArgumentException("Offline player not allowed"); - } - if (selection == null) { - throw new IllegalArgumentException("Null selection not allowed"); - } - - LocalSession session = controller.getSession(wrapPlayer(player)); - RegionSelector sel = selection.getRegionSelector(); - session.setRegionSelector(BukkitUtil.getLocalWorld(player.getWorld()), sel); - session.dispatchCUISelection(wrapPlayer(player)); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.bukkit; + +import com.sk89q.util.yaml.YAMLProcessor; +import com.sk89q.wepif.PermissionsResolverManager; +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.bukkit.selections.CuboidSelection; +import com.sk89q.worldedit.bukkit.selections.Polygonal2DSelection; +import com.sk89q.worldedit.bukkit.selections.Selection; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Polygonal2DRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.selector.RegionSelector; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.*; +import java.util.Enumeration; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.logging.Handler; +import java.util.zip.ZipEntry; + +/** + * Plugin for Bukkit. + * + * @author sk89q + */ +public class WorldEditPlugin extends JavaPlugin { + + /** + * The name of the CUI's plugin channel registration + */ + public static final String CUI_PLUGIN_CHANNEL = "WECUI"; + + /** + * The server interface that all server-related API goes through. + */ + private BukkitServerInterface server; + /** + * Main WorldEdit instance. + */ + private WorldEdit controller; + /** + * Deprecated API. + */ + private WorldEditAPI api; + + /** + * Holds the configuration for WorldEdit. + */ + private BukkitConfiguration config; + + /** + * Called on plugin enable. + */ + @Override + public void onEnable() { + final String pluginYmlVersion = getDescription().getVersion(); + final String manifestVersion = WorldEdit.getVersion(); + + if (!manifestVersion.equalsIgnoreCase(pluginYmlVersion)) { + WorldEdit.setVersion(manifestVersion + " (" + pluginYmlVersion + ")"); + } + + // Make the data folders that WorldEdit uses + getDataFolder().mkdirs(); + File targetDir = new File(getDataFolder() + File.separator + "nmsblocks"); + targetDir.mkdir(); + copyNmsBlockClasses(targetDir); + + // Create the default configuration file + createDefaultConfiguration("config.yml"); + + // Set up configuration and such, including the permissions + // resolver + config = new BukkitConfiguration(new YAMLProcessor(new File(getDataFolder(), "config.yml"), true), this); + PermissionsResolverManager.initialize(this); + + // Load the configuration + config.load(); + + // Setup interfaces + server = new BukkitServerInterface(this, getServer()); + controller = new WorldEdit(server, config); + WorldEdit.logger.setParent(Bukkit.getLogger()); + api = new WorldEditAPI(this); + getServer().getMessenger().registerIncomingPluginChannel(this, CUI_PLUGIN_CHANNEL, new CUIChannelListener(this)); + getServer().getMessenger().registerOutgoingPluginChannel(this, CUI_PLUGIN_CHANNEL); + // Now we can register events! + getServer().getPluginManager().registerEvents(new WorldEditListener(this), this); + + getServer().getScheduler().runTaskTimerAsynchronously(this, + new SessionTimer(controller, getServer()), 120, 120); + } + + private void copyNmsBlockClasses(File target) { + try { + JarFile jar = new JarFile(getFile()); + @SuppressWarnings("rawtypes") + Enumeration entries = jar.entries(); + while (entries.hasMoreElements()) { + JarEntry jarEntry = (JarEntry) entries.nextElement(); + if (!jarEntry.getName().startsWith("nmsblocks") || jarEntry.isDirectory()) continue; + + File file = new File(target + File.separator + jarEntry.getName().replace("nmsblocks", "")); + if (file.exists()) continue; + + InputStream is = jar.getInputStream(jarEntry); + FileOutputStream fos = new FileOutputStream(file); + + fos = new FileOutputStream(file); + byte[] buf = new byte[8192]; + int length = 0; + while ((length = is.read(buf)) > 0) { + fos.write(buf, 0, length); + } + fos.close(); + is.close(); + } + } catch (Throwable e) {} + } + + /** + * Called on plugin disable. + */ + @Override + public void onDisable() { + controller.clearSessions(); + for (Handler h : controller.commandLogger.getHandlers()) { + h.close(); + } + config.unload(); + server.unregisterCommands(); + this.getServer().getScheduler().cancelTasks(this); + } + + /** + * Loads and reloads all configuration. + */ + protected void loadConfiguration() { + config.unload(); + config.load(); + getPermissionsResolver().load(); + } + + /** + * Create a default configuration file from the .jar. + * + * @param name + */ + protected void createDefaultConfiguration(String name) { + File actual = new File(getDataFolder(), name); + if (!actual.exists()) { + InputStream input = + null; + try { + JarFile file = new JarFile(getFile()); + ZipEntry copy = file.getEntry("defaults/" + name); + if (copy == null) throw new FileNotFoundException(); + input = file.getInputStream(copy); + } catch (IOException e) { + getLogger().severe("Unable to read default configuration: " + name); + } + if (input != null) { + FileOutputStream output = null; + + try { + output = new FileOutputStream(actual); + byte[] buf = new byte[8192]; + int length = 0; + while ((length = input.read(buf)) > 0) { + output.write(buf, 0, length); + } + + getLogger().info("Default configuration file written: " + name); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (input != null) { + input.close(); + } + } catch (IOException e) {} + + try { + if (output != null) { + output.close(); + } + } catch (IOException e) {} + } + } + } + } + + /** + * Called on WorldEdit command. + */ + @Override + public boolean onCommand(CommandSender sender, org.bukkit.command.Command cmd, + String commandLabel, String[] args) { + + // Add the command to the array because the underlying command handling + // code of WorldEdit expects it + String[] split = new String[args.length + 1]; + System.arraycopy(args, 0, split, 1, args.length); + split[0] = "/" + cmd.getName(); + + controller.handleCommand(wrapCommandSender(sender), split); + + return true; + } + + /** + * Gets the session for the player. + * + * @param player + * @return + */ + public LocalSession getSession(Player player) { + return controller.getSession(wrapPlayer(player)); + } + + /** + * Gets the session for the player. + * + * @param player + * @return + */ + public EditSession createEditSession(Player player) { + LocalPlayer wePlayer = wrapPlayer(player); + LocalSession session = controller.getSession(wePlayer); + BlockBag blockBag = session.getBlockBag(wePlayer); + + EditSession editSession = controller.getEditSessionFactory() + .getEditSession(wePlayer.getWorld(), session.getBlockChangeLimit(), blockBag, wePlayer); + editSession.enableQueue(); + + return editSession; + } + + /** + * Remember an edit session. + * + * @param player + * @param editSession + */ + public void remember(Player player, EditSession editSession) { + LocalPlayer wePlayer = wrapPlayer(player); + LocalSession session = controller.getSession(wePlayer); + + session.remember(editSession); + editSession.flushQueue(); + + controller.flushBlockBag(wePlayer, editSession); + } + + /** + * Wrap an operation into an EditSession. + * + * @param player + * @param op + * @throws Throwable + */ + public void perform(Player player, WorldEditOperation op) + throws Throwable { + LocalPlayer wePlayer = wrapPlayer(player); + LocalSession session = controller.getSession(wePlayer); + + EditSession editSession = createEditSession(player); + try { + op.run(session, wePlayer, editSession); + } finally { + remember(player, editSession); + } + } + + /** + * Get the API. + * + * @return + */ + @Deprecated + public WorldEditAPI getAPI() { + return api; + } + + /** + * Returns the configuration used by WorldEdit. + * + * @return + */ + public BukkitConfiguration getLocalConfiguration() { + return config; + } + + /** + * Get the permissions resolver in use. + * + * @return + */ + public PermissionsResolverManager getPermissionsResolver() { + return PermissionsResolverManager.getInstance(); + } + + /** + * Used to wrap a Bukkit Player as a LocalPlayer. + * + * @param player + * @return + */ + public BukkitPlayer wrapPlayer(Player player) { + return new BukkitPlayer(this, this.server, player); + } + + public LocalPlayer wrapCommandSender(CommandSender sender) { + if (sender instanceof Player) { + return wrapPlayer((Player) sender); + } + + return new BukkitCommandSender(this, this.server, sender); + } + + /** + * Get the server interface. + * + * @return + */ + public ServerInterface getServerInterface() { + return server; + } + + /** + * Get WorldEdit. + * + * @return + */ + public WorldEdit getWorldEdit() { + return controller; + } + + /** + * Gets the region selection for the player. + * + * @param player + * @return the selection or null if there was none + */ + public Selection getSelection(Player player) { + if (player == null) { + throw new IllegalArgumentException("Null player not allowed"); + } + if (!player.isOnline()) { + throw new IllegalArgumentException("Offline player not allowed"); + } + + LocalSession session = controller.getSession(wrapPlayer(player)); + RegionSelector selector = session.getRegionSelector(BukkitUtil.getLocalWorld(player.getWorld())); + + try { + Region region = selector.getRegion(); + World world = ((BukkitWorld) session.getSelectionWorld()).getWorld(); + + if (region instanceof CuboidRegion) { + return new CuboidSelection(world, selector, (CuboidRegion) region); + } else if (region instanceof Polygonal2DRegion) { + return new Polygonal2DSelection(world, selector, (Polygonal2DRegion) region); + } else { + return null; + } + } catch (IncompleteRegionException e) { + return null; + } + } + + /** + * Sets the region selection for a player. + * + * @param player + * @param selection + */ + public void setSelection(Player player, Selection selection) { + if (player == null) { + throw new IllegalArgumentException("Null player not allowed"); + } + if (!player.isOnline()) { + throw new IllegalArgumentException("Offline player not allowed"); + } + if (selection == null) { + throw new IllegalArgumentException("Null selection not allowed"); + } + + LocalSession session = controller.getSession(wrapPlayer(player)); + RegionSelector sel = selection.getRegionSelector(); + session.setRegionSelector(BukkitUtil.getLocalWorld(player.getWorld()), sel); + session.dispatchCUISelection(wrapPlayer(player)); + } +} diff --git a/src/main/java/com/sk89q/worldedit/bukkit/entity/BukkitEntity.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/entity/BukkitEntity.java similarity index 100% rename from src/main/java/com/sk89q/worldedit/bukkit/entity/BukkitEntity.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/entity/BukkitEntity.java diff --git a/src/main/java/com/sk89q/worldedit/bukkit/entity/BukkitExpOrb.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/entity/BukkitExpOrb.java similarity index 100% rename from src/main/java/com/sk89q/worldedit/bukkit/entity/BukkitExpOrb.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/entity/BukkitExpOrb.java diff --git a/src/main/java/com/sk89q/worldedit/bukkit/entity/BukkitItem.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/entity/BukkitItem.java similarity index 100% rename from src/main/java/com/sk89q/worldedit/bukkit/entity/BukkitItem.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/entity/BukkitItem.java diff --git a/src/main/java/com/sk89q/worldedit/bukkit/entity/BukkitPainting.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/entity/BukkitPainting.java similarity index 100% rename from src/main/java/com/sk89q/worldedit/bukkit/entity/BukkitPainting.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/entity/BukkitPainting.java diff --git a/src/main/java/com/sk89q/worldedit/bukkit/selections/CuboidSelection.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/selections/CuboidSelection.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/bukkit/selections/CuboidSelection.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/selections/CuboidSelection.java index 857689af2..1ee663bf7 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/selections/CuboidSelection.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/selections/CuboidSelection.java @@ -1,67 +1,69 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.bukkit.selections; - -import org.bukkit.Location; -import org.bukkit.World; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.bukkit.BukkitUtil; -import com.sk89q.worldedit.regions.*; - -public class CuboidSelection extends RegionSelection { - - protected CuboidRegion cuboid; - - public CuboidSelection(World world, Location pt1, Location pt2) { - this(world, BukkitUtil.toVector(pt1), BukkitUtil.toVector(pt2)); - } - - public CuboidSelection(World world, Vector pt1, Vector pt2) { - super(world); - - // Validate input - if (pt1 == null) { - throw new IllegalArgumentException("Null point 1 not permitted"); - } - - if (pt2 == null) { - throw new IllegalArgumentException("Null point 2 not permitted"); - } - - // Create new selector - CuboidRegionSelector sel = new CuboidRegionSelector(BukkitUtil.getLocalWorld(world)); - - // set up selector - sel.selectPrimary(pt1); - sel.selectSecondary(pt2); - - // set up CuboidSelection - cuboid = sel.getIncompleteRegion(); - - // set up RegionSelection - setRegionSelector(sel); - setRegion(cuboid); - } - - public CuboidSelection(World world, RegionSelector sel, CuboidRegion region) { - super(world, sel, region); - this.cuboid = region; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.bukkit.selections; + +import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; +import com.sk89q.worldedit.regions.selector.RegionSelector; +import org.bukkit.Location; +import org.bukkit.World; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.bukkit.BukkitUtil; +import com.sk89q.worldedit.regions.*; + +public class CuboidSelection extends RegionSelection { + + protected CuboidRegion cuboid; + + public CuboidSelection(World world, Location pt1, Location pt2) { + this(world, BukkitUtil.toVector(pt1), BukkitUtil.toVector(pt2)); + } + + public CuboidSelection(World world, Vector pt1, Vector pt2) { + super(world); + + // Validate input + if (pt1 == null) { + throw new IllegalArgumentException("Null point 1 not permitted"); + } + + if (pt2 == null) { + throw new IllegalArgumentException("Null point 2 not permitted"); + } + + // Create new selector + CuboidRegionSelector sel = new CuboidRegionSelector(BukkitUtil.getLocalWorld(world)); + + // set up selector + sel.selectPrimary(pt1); + sel.selectSecondary(pt2); + + // set up CuboidSelection + cuboid = sel.getIncompleteRegion(); + + // set up RegionSelection + setRegionSelector(sel); + setRegion(cuboid); + } + + public CuboidSelection(World world, RegionSelector sel, CuboidRegion region) { + super(world, sel, region); + this.cuboid = region; + } +} diff --git a/src/main/java/com/sk89q/worldedit/bukkit/selections/Polygonal2DSelection.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/selections/Polygonal2DSelection.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/bukkit/selections/Polygonal2DSelection.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/selections/Polygonal2DSelection.java index 6a6107add..07476a020 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/selections/Polygonal2DSelection.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/selections/Polygonal2DSelection.java @@ -1,62 +1,64 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.bukkit.selections; - -import java.util.Collections; -import java.util.List; - -import com.sk89q.worldedit.LocalWorld; -import org.bukkit.World; -import com.sk89q.worldedit.BlockVector2D; -import com.sk89q.worldedit.bukkit.BukkitUtil; -import com.sk89q.worldedit.regions.*; - -public class Polygonal2DSelection extends RegionSelection { - - protected Polygonal2DRegion poly2d; - - public Polygonal2DSelection(World world, RegionSelector sel, Polygonal2DRegion region) { - super(world, sel, region); - this.poly2d = region; - } - - public Polygonal2DSelection(World world, List points, int minY, int maxY) { - super(world); - LocalWorld lWorld = BukkitUtil.getLocalWorld(world); - - // Validate input - minY = Math.min(Math.max(0, minY), world.getMaxHeight()); - maxY = Math.min(Math.max(0, maxY), world.getMaxHeight()); - - // Create and set up new selector - Polygonal2DRegionSelector sel = new Polygonal2DRegionSelector(lWorld, points, minY, maxY); - - // set up CuboidSelection - poly2d = sel.getIncompleteRegion(); - - // set up RegionSelection - setRegionSelector(sel); - setRegion(poly2d); - } - - public List getNativePoints() { - return Collections.unmodifiableList(poly2d.getPoints()); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.bukkit.selections; + +import java.util.Collections; +import java.util.List; + +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.regions.selector.Polygonal2DRegionSelector; +import com.sk89q.worldedit.regions.selector.RegionSelector; +import org.bukkit.World; +import com.sk89q.worldedit.BlockVector2D; +import com.sk89q.worldedit.bukkit.BukkitUtil; +import com.sk89q.worldedit.regions.*; + +public class Polygonal2DSelection extends RegionSelection { + + protected Polygonal2DRegion poly2d; + + public Polygonal2DSelection(World world, RegionSelector sel, Polygonal2DRegion region) { + super(world, sel, region); + this.poly2d = region; + } + + public Polygonal2DSelection(World world, List points, int minY, int maxY) { + super(world); + LocalWorld lWorld = BukkitUtil.getLocalWorld(world); + + // Validate input + minY = Math.min(Math.max(0, minY), world.getMaxHeight()); + maxY = Math.min(Math.max(0, maxY), world.getMaxHeight()); + + // Create and set up new selector + Polygonal2DRegionSelector sel = new Polygonal2DRegionSelector(lWorld, points, minY, maxY); + + // set up CuboidSelection + poly2d = sel.getIncompleteRegion(); + + // set up RegionSelection + setRegionSelector(sel); + setRegion(poly2d); + } + + public List getNativePoints() { + return Collections.unmodifiableList(poly2d.getPoints()); + } +} diff --git a/src/main/java/com/sk89q/worldedit/bukkit/selections/RegionSelection.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/selections/RegionSelection.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/bukkit/selections/RegionSelection.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/selections/RegionSelection.java index a50f28878..4385c1ba5 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/selections/RegionSelection.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/selections/RegionSelection.java @@ -1,106 +1,107 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.bukkit.selections; - -import static com.sk89q.worldedit.bukkit.BukkitUtil.toLocation; -import static com.sk89q.worldedit.bukkit.BukkitUtil.toVector; -import org.bukkit.Location; -import org.bukkit.World; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.regions.RegionSelector; - -public abstract class RegionSelection implements Selection { - - private World world; - private RegionSelector selector; - private Region region; - - public RegionSelection(World world) { - this.world = world; - } - - public RegionSelection(World world, RegionSelector selector, Region region) { - this.world = world; - this.region = region; - this.selector = selector; - } - - protected Region getRegion() { - return region; - } - - protected void setRegion(Region region) { - this.region = region; - } - - public RegionSelector getRegionSelector() { - return selector; - } - - protected void setRegionSelector(RegionSelector selector) { - this.selector = selector; - } - - public Location getMinimumPoint() { - return toLocation(world, region.getMinimumPoint()); - } - - public Vector getNativeMinimumPoint() { - return region.getMinimumPoint(); - } - - public Location getMaximumPoint() { - return toLocation(world, region.getMaximumPoint()); - } - - public Vector getNativeMaximumPoint() { - return region.getMaximumPoint(); - } - - public World getWorld() { - return world; - } - - public int getArea() { - return region.getArea(); - } - - public int getWidth() { - return region.getWidth(); - } - - public int getHeight() { - return region.getHeight(); - } - - public int getLength() { - return region.getLength(); - } - - public boolean contains(Location pt) { - if (!pt.getWorld().equals(world)) { - return false; - } - - return region.contains(toVector(pt)); - } - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.bukkit.selections; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.selector.RegionSelector; +import org.bukkit.Location; +import org.bukkit.World; + +import static com.sk89q.worldedit.bukkit.BukkitUtil.toLocation; +import static com.sk89q.worldedit.bukkit.BukkitUtil.toVector; + +public abstract class RegionSelection implements Selection { + + private World world; + private RegionSelector selector; + private Region region; + + public RegionSelection(World world) { + this.world = world; + } + + public RegionSelection(World world, RegionSelector selector, Region region) { + this.world = world; + this.region = region; + this.selector = selector; + } + + protected Region getRegion() { + return region; + } + + protected void setRegion(Region region) { + this.region = region; + } + + public RegionSelector getRegionSelector() { + return selector; + } + + protected void setRegionSelector(RegionSelector selector) { + this.selector = selector; + } + + public Location getMinimumPoint() { + return toLocation(world, region.getMinimumPoint()); + } + + public Vector getNativeMinimumPoint() { + return region.getMinimumPoint(); + } + + public Location getMaximumPoint() { + return toLocation(world, region.getMaximumPoint()); + } + + public Vector getNativeMaximumPoint() { + return region.getMaximumPoint(); + } + + public World getWorld() { + return world; + } + + public int getArea() { + return region.getArea(); + } + + public int getWidth() { + return region.getWidth(); + } + + public int getHeight() { + return region.getHeight(); + } + + public int getLength() { + return region.getLength(); + } + + public boolean contains(Location pt) { + if (!pt.getWorld().equals(world)) { + return false; + } + + return region.contains(toVector(pt)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/bukkit/selections/Selection.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/selections/Selection.java similarity index 93% rename from src/main/java/com/sk89q/worldedit/bukkit/selections/Selection.java rename to src/bukkit/java/com/sk89q/worldedit/bukkit/selections/Selection.java index baa4c039e..7195047cc 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/selections/Selection.java +++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/selections/Selection.java @@ -1,105 +1,105 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.bukkit.selections; - -import org.bukkit.Location; -import org.bukkit.World; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.regions.RegionSelector; - -public interface Selection { - /** - * Get the lower point of a region. - * - * @return min. point - */ - public Location getMinimumPoint(); - - /** - * Get the lower point of a region. - * - * @return min. point - */ - public Vector getNativeMinimumPoint(); - - /** - * Get the upper point of a region. - * - * @return max. point - */ - public Location getMaximumPoint(); - - /** - * Get the upper point of a region. - * - * @return max. point - */ - public Vector getNativeMaximumPoint(); - - /** - * Get the region selector. This is for internal use. - * - * @return - */ - public RegionSelector getRegionSelector(); - - /** - * Get the world. - * - * @return - */ - public World getWorld(); - - /** - * Get the number of blocks in the region. - * - * @return number of blocks - */ - public int getArea(); - - /** - * Get X-size. - * - * @return width - */ - public int getWidth(); - - /** - * Get Y-size. - * - * @return height - */ - public int getHeight(); - - /** - * Get Z-size. - * - * @return length - */ - public int getLength(); - - /** - * Returns true based on whether the region contains the point, - * - * @param pt - * @return - */ - public boolean contains(Location pt); -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.bukkit.selections; + +import org.bukkit.Location; +import org.bukkit.World; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.regions.selector.RegionSelector; + +public interface Selection { + /** + * Get the lower point of a region. + * + * @return min. point + */ + public Location getMinimumPoint(); + + /** + * Get the lower point of a region. + * + * @return min. point + */ + public Vector getNativeMinimumPoint(); + + /** + * Get the upper point of a region. + * + * @return max. point + */ + public Location getMaximumPoint(); + + /** + * Get the upper point of a region. + * + * @return max. point + */ + public Vector getNativeMaximumPoint(); + + /** + * Get the region selector. This is for internal use. + * + * @return + */ + public RegionSelector getRegionSelector(); + + /** + * Get the world. + * + * @return + */ + public World getWorld(); + + /** + * Get the number of blocks in the region. + * + * @return number of blocks + */ + public int getArea(); + + /** + * Get X-size. + * + * @return width + */ + public int getWidth(); + + /** + * Get Y-size. + * + * @return height + */ + public int getHeight(); + + /** + * Get Z-size. + * + * @return length + */ + public int getLength(); + + /** + * Returns true based on whether the region contains the point, + * + * @param pt + * @return + */ + public boolean contains(Location pt); +} diff --git a/src/main/resources/config.yml b/src/bukkit/resources/config.yml similarity index 96% rename from src/main/resources/config.yml rename to src/bukkit/resources/config.yml index f4c7c2981..913a0decc 100644 --- a/src/main/resources/config.yml +++ b/src/bukkit/resources/config.yml @@ -1,72 +1,72 @@ -# -# WorldEdit's configuration file -# -# About editing this file: -# - DO NOT USE TABS. You MUST use spaces or Bukkit will complain. If -# you use an editor like Notepad++ (recommended for Windows users), you -# must configure it to "replace tabs with spaces." In Notepad++, this can -# be changed in Settings > Preferences > Language Menu. -# - Don't get rid of the indents. They are indented so some entries are -# in categories (like "max-blocks-changed" is in the "limits" -# category. -# - If you want to check the format of this file before putting it -# into WorldEdit, paste it into http://yaml-online-parser.appspot.com/ -# and see if it gives "ERROR:". -# - Lines starting with # are commentsand so they are ignored. -# - -limits: - allow-extra-data-values: false - max-blocks-changed: - default: -1 - maximum: -1 - max-polygonal-points: - default: -1 - maximum: 20 - max-radius: -1 - max-super-pickaxe-size: 5 - max-brush-radius: 5 - butcher-radius: - default: -1 - maximum: -1 - disallowed-blocks: [6, 7, 14, 15, 16, 26, 27, 28, 29, 39, 31, 32, 33, 34, 36, 37, 38, 39, 40, 46, 50, 51, 56, 59, 69, 73, 74, 75, 76, 77, 81, 83] - -use-inventory: - enable: false - allow-override: true - creative-mode-overrides: false - -logging: - log-commands: false - file: worldedit.log - -super-pickaxe: - drop-items: true - many-drop-items: false - -snapshots: - directory: - -navigation-wand: - item: 345 - max-distance: 100 - -scripting: - timeout: 3000 - dir: craftscripts - -saving: - dir: schematics - -files: - allow-symbolic-links: false - -history: - size: 15 - expiration: 10 - -wand-item: 271 -shell-save-type: -no-double-slash: false -no-op-permissions: false -debug: false +# +# WorldEdit's configuration file +# +# About editing this file: +# - DO NOT USE TABS. You MUST use spaces or Bukkit will complain. If +# you use an editor like Notepad++ (recommended for Windows users), you +# must configure it to "replace tabs with spaces." In Notepad++, this can +# be changed in Settings > Preferences > Language Menu. +# - Don't get rid of the indents. They are indented so some entries are +# in categories (like "max-blocks-changed" is in the "limits" +# category. +# - If you want to check the format of this file before putting it +# into WorldEdit, paste it into http://yaml-online-parser.appspot.com/ +# and see if it gives "ERROR:". +# - Lines starting with # are commentsand so they are ignored. +# + +limits: + allow-extra-data-values: false + max-blocks-changed: + default: -1 + maximum: -1 + max-polygonal-points: + default: -1 + maximum: 20 + max-radius: -1 + max-super-pickaxe-size: 5 + max-brush-radius: 5 + butcher-radius: + default: -1 + maximum: -1 + disallowed-blocks: [6, 7, 14, 15, 16, 26, 27, 28, 29, 39, 31, 32, 33, 34, 36, 37, 38, 39, 40, 46, 50, 51, 56, 59, 69, 73, 74, 75, 76, 77, 81, 83] + +use-inventory: + enable: false + allow-override: true + creative-mode-overrides: false + +logging: + log-commands: false + file: worldedit.log + +super-pickaxe: + drop-items: true + many-drop-items: false + +snapshots: + directory: + +navigation-wand: + item: 345 + max-distance: 100 + +scripting: + timeout: 3000 + dir: craftscripts + +saving: + dir: schematics + +files: + allow-symbolic-links: false + +history: + size: 15 + expiration: 10 + +wand-item: 271 +shell-save-type: +no-double-slash: false +no-op-permissions: false +debug: false diff --git a/src/main/resources/nmsblocks/CBXNmsBlock_145.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_145.class similarity index 100% rename from src/main/resources/nmsblocks/CBXNmsBlock_145.class rename to src/bukkit/resources/nmsblocks/CBXNmsBlock_145.class diff --git a/src/main/resources/nmsblocks/CBXNmsBlock_146.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_146.class similarity index 100% rename from src/main/resources/nmsblocks/CBXNmsBlock_146.class rename to src/bukkit/resources/nmsblocks/CBXNmsBlock_146.class diff --git a/src/main/resources/nmsblocks/CBXNmsBlock_147.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_147.class similarity index 100% rename from src/main/resources/nmsblocks/CBXNmsBlock_147.class rename to src/bukkit/resources/nmsblocks/CBXNmsBlock_147.class diff --git a/src/main/resources/nmsblocks/CBXNmsBlock_15.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_15.class similarity index 100% rename from src/main/resources/nmsblocks/CBXNmsBlock_15.class rename to src/bukkit/resources/nmsblocks/CBXNmsBlock_15.class diff --git a/src/main/resources/nmsblocks/CBXNmsBlock_152.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_152.class similarity index 100% rename from src/main/resources/nmsblocks/CBXNmsBlock_152.class rename to src/bukkit/resources/nmsblocks/CBXNmsBlock_152.class diff --git a/src/main/resources/nmsblocks/CBXNmsBlock_161.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_161.class similarity index 100% rename from src/main/resources/nmsblocks/CBXNmsBlock_161.class rename to src/bukkit/resources/nmsblocks/CBXNmsBlock_161.class diff --git a/src/main/resources/nmsblocks/CBXNmsBlock_162.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_162.class similarity index 100% rename from src/main/resources/nmsblocks/CBXNmsBlock_162.class rename to src/bukkit/resources/nmsblocks/CBXNmsBlock_162.class diff --git a/src/main/resources/nmsblocks/CBXNmsBlock_164.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_164.class similarity index 100% rename from src/main/resources/nmsblocks/CBXNmsBlock_164.class rename to src/bukkit/resources/nmsblocks/CBXNmsBlock_164.class diff --git a/src/main/resources/nmsblocks/CBXNmsBlock_172.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_172.class similarity index 100% rename from src/main/resources/nmsblocks/CBXNmsBlock_172.class rename to src/bukkit/resources/nmsblocks/CBXNmsBlock_172.class diff --git a/src/main/resources/nmsblocks/CBXNmsBlock_175.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_175.class similarity index 100% rename from src/main/resources/nmsblocks/CBXNmsBlock_175.class rename to src/bukkit/resources/nmsblocks/CBXNmsBlock_175.class diff --git a/src/main/resources/nmsblocks/CBXNmsBlock_prePackage.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_prePackage.class similarity index 100% rename from src/main/resources/nmsblocks/CBXNmsBlock_prePackage.class rename to src/bukkit/resources/nmsblocks/CBXNmsBlock_prePackage.class diff --git a/src/main/resources/nmsblocks/CBXNmsBlock_v152_2.class b/src/bukkit/resources/nmsblocks/CBXNmsBlock_v152_2.class similarity index 100% rename from src/main/resources/nmsblocks/CBXNmsBlock_v152_2.class rename to src/bukkit/resources/nmsblocks/CBXNmsBlock_v152_2.class diff --git a/src/main/resources/nmsblocks/MCPCPlusXNmsBlock_147.class b/src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_147.class similarity index 100% rename from src/main/resources/nmsblocks/MCPCPlusXNmsBlock_147.class rename to src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_147.class diff --git a/src/main/resources/nmsblocks/MCPCPlusXNmsBlock_151dv.class b/src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_151dv.class similarity index 100% rename from src/main/resources/nmsblocks/MCPCPlusXNmsBlock_151dv.class rename to src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_151dv.class diff --git a/src/main/resources/nmsblocks/MCPCPlusXNmsBlock_162.class b/src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_162.class similarity index 100% rename from src/main/resources/nmsblocks/MCPCPlusXNmsBlock_162.class rename to src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_162.class diff --git a/src/main/resources/nmsblocks/MCPCPlusXNmsBlock_164.class b/src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_164.class similarity index 100% rename from src/main/resources/nmsblocks/MCPCPlusXNmsBlock_164.class rename to src/bukkit/resources/nmsblocks/MCPCPlusXNmsBlock_164.class diff --git a/src/main/resources/plugin.yml b/src/bukkit/resources/plugin.yml similarity index 100% rename from src/main/resources/plugin.yml rename to src/bukkit/resources/plugin.yml diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java b/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java index 1397e5654..1ef75c30e 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java +++ b/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java @@ -10,8 +10,8 @@ import com.sk89q.worldedit.LocalPlayer; import com.sk89q.worldedit.LocalWorld; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldVector; -import com.sk89q.worldedit.bags.BlockBag; -import com.sk89q.worldedit.cui.CUIEvent; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.internal.cui.CUIEvent; public class ForgePlayer extends LocalPlayer { private EntityPlayerMP player; diff --git a/src/forge/java/com/sk89q/worldedit/forge/selections/CuboidSelection.java b/src/forge/java/com/sk89q/worldedit/forge/selections/CuboidSelection.java index dcdad00de..2e49242c7 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/selections/CuboidSelection.java +++ b/src/forge/java/com/sk89q/worldedit/forge/selections/CuboidSelection.java @@ -6,8 +6,8 @@ import com.sk89q.worldedit.Location; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.forge.WorldEditMod; import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.regions.CuboidRegionSelector; -import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; +import com.sk89q.worldedit.regions.selector.RegionSelector; public class CuboidSelection extends RegionSelection { protected CuboidRegion cuboid; diff --git a/src/forge/java/com/sk89q/worldedit/forge/selections/Polygonal2DSelection.java b/src/forge/java/com/sk89q/worldedit/forge/selections/Polygonal2DSelection.java index d54828dad..5b46c63b2 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/selections/Polygonal2DSelection.java +++ b/src/forge/java/com/sk89q/worldedit/forge/selections/Polygonal2DSelection.java @@ -8,8 +8,8 @@ import net.minecraft.world.World; import com.sk89q.worldedit.LocalWorld; import com.sk89q.worldedit.forge.WorldEditMod; import com.sk89q.worldedit.regions.Polygonal2DRegion; -import com.sk89q.worldedit.regions.Polygonal2DRegionSelector; -import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.Polygonal2DRegionSelector; +import com.sk89q.worldedit.regions.selector.RegionSelector; public class Polygonal2DSelection extends RegionSelection { protected Polygonal2DRegion poly2d; diff --git a/src/forge/java/com/sk89q/worldedit/forge/selections/RegionSelection.java b/src/forge/java/com/sk89q/worldedit/forge/selections/RegionSelection.java index b04fb416c..a42f391be 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/selections/RegionSelection.java +++ b/src/forge/java/com/sk89q/worldedit/forge/selections/RegionSelection.java @@ -8,7 +8,7 @@ import com.sk89q.worldedit.Location; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.forge.WorldEditMod; import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.RegionSelector; public abstract class RegionSelection implements Selection { private WeakReference world; diff --git a/src/forge/java/com/sk89q/worldedit/forge/selections/Selection.java b/src/forge/java/com/sk89q/worldedit/forge/selections/Selection.java index 815b5a530..0c6dfa5ad 100644 --- a/src/forge/java/com/sk89q/worldedit/forge/selections/Selection.java +++ b/src/forge/java/com/sk89q/worldedit/forge/selections/Selection.java @@ -4,7 +4,7 @@ import net.minecraft.world.World; import com.sk89q.worldedit.Location; import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.RegionSelector; public abstract interface Selection { public abstract Location getMinimumPoint(); diff --git a/src/legacy/java/com/sk89q/worldedit/data/DataException.java b/src/legacy/java/com/sk89q/worldedit/data/DataException.java new file mode 100644 index 000000000..d907cde5e --- /dev/null +++ b/src/legacy/java/com/sk89q/worldedit/data/DataException.java @@ -0,0 +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 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.data; + +/** + * @deprecated Switch to {@link com.sk89q.worldedit.world.DataException} + */ +@Deprecated +public class DataException extends com.sk89q.worldedit.world.DataException { +} diff --git a/src/legacy/java/com/sk89q/worldedit/foundation/Block.java b/src/legacy/java/com/sk89q/worldedit/foundation/Block.java new file mode 100644 index 000000000..44085daea --- /dev/null +++ b/src/legacy/java/com/sk89q/worldedit/foundation/Block.java @@ -0,0 +1,41 @@ +// $Id$ +/* + * This file is a part of WorldEdit. + * Copyright (c) sk89q + * Copyright (c) the 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 + * (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 + * 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 . +*/ + +package com.sk89q.worldedit.foundation; + +import com.sk89q.worldedit.blocks.BaseBlock; + +/** + * @deprecated Use {@link BaseBlock} + */ +@Deprecated +public abstract class Block { + + public abstract int getId(); + + public abstract void setId(int id); + + public abstract int getData(); + + public abstract void setData(int data); + + public abstract void setIdAndData(int id, int data); + + public abstract boolean hasWildcardData(); + +} diff --git a/src/main/java/com/sk89q/worldedit/masks/AbstractMask.java b/src/legacy/java/com/sk89q/worldedit/masks/AbstractMask.java similarity index 75% rename from src/main/java/com/sk89q/worldedit/masks/AbstractMask.java rename to src/legacy/java/com/sk89q/worldedit/masks/AbstractMask.java index 0be57ccab..07ba3c176 100644 --- a/src/main/java/com/sk89q/worldedit/masks/AbstractMask.java +++ b/src/legacy/java/com/sk89q/worldedit/masks/AbstractMask.java @@ -1,11 +1,16 @@ -package com.sk89q.worldedit.masks; - -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.Vector; - -public abstract class AbstractMask implements Mask { - @Override - public void prepare(LocalSession session, LocalPlayer player, Vector target) { - } -} +package com.sk89q.worldedit.masks; + +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.Vector; + +/** + * @deprecated Switch to {@link com.sk89q.worldedit.function.mask.AbstractMask} + */ +@Deprecated +public abstract class AbstractMask implements Mask { + @Override + public void prepare(LocalSession session, LocalPlayer player, Vector target) { + } + +} diff --git a/src/main/java/com/sk89q/worldedit/masks/BiomeTypeMask.java b/src/legacy/java/com/sk89q/worldedit/masks/BiomeTypeMask.java similarity index 100% rename from src/main/java/com/sk89q/worldedit/masks/BiomeTypeMask.java rename to src/legacy/java/com/sk89q/worldedit/masks/BiomeTypeMask.java diff --git a/src/main/java/com/sk89q/worldedit/masks/BlockMask.java b/src/legacy/java/com/sk89q/worldedit/masks/BlockMask.java similarity index 75% rename from src/main/java/com/sk89q/worldedit/masks/BlockMask.java rename to src/legacy/java/com/sk89q/worldedit/masks/BlockMask.java index e852a9990..c6d9a922e 100644 --- a/src/main/java/com/sk89q/worldedit/masks/BlockMask.java +++ b/src/legacy/java/com/sk89q/worldedit/masks/BlockMask.java @@ -1,14 +1,19 @@ package com.sk89q.worldedit.masks; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BaseBlock; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +/** + * @deprecated Use {@link com.sk89q.worldedit.function.mask.BlockMask} + */ +@Deprecated public class BlockMask extends AbstractMask { + private final Set blocks; public BlockMask() { @@ -19,6 +24,13 @@ public class BlockMask extends AbstractMask { this.blocks = types; } + public BlockMask(BaseBlock... block) { + blocks = new HashSet(); + for (BaseBlock b : block) { + add(b); + } + } + public BlockMask(BaseBlock block) { this(); add(block); @@ -35,7 +47,8 @@ public class BlockMask extends AbstractMask { @Override public boolean matches(EditSession editSession, Vector pos) { BaseBlock block = editSession.getBlock(pos); - return blocks.contains(block) + return blocks.contains(block) || blocks.contains(new BaseBlock(block.getType(), -1)); - } + } + } diff --git a/src/main/java/com/sk89q/worldedit/masks/BlockTypeMask.java b/src/legacy/java/com/sk89q/worldedit/masks/BlockTypeMask.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/masks/BlockTypeMask.java rename to src/legacy/java/com/sk89q/worldedit/masks/BlockTypeMask.java index 5a9dee9fc..c4df2671c 100644 --- a/src/main/java/com/sk89q/worldedit/masks/BlockTypeMask.java +++ b/src/legacy/java/com/sk89q/worldedit/masks/BlockTypeMask.java @@ -1,52 +1,52 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.masks; - -import java.util.Set; -import com.sk89q.worldedit.blocks.BaseBlock; - -/** - * A filter that matches blocks based on block types. - * - * @deprecated replaced by {@link #BlockMask} - * @author sk89q - */ -@Deprecated -public class BlockTypeMask extends BlockMask { - public BlockTypeMask() { - super(); - } - - public BlockTypeMask(Set types) { - super(); - for (int type : types) { - add(type); - } - } - - public BlockTypeMask(int type) { - this(); - add(type); - } - - public void add(int type) { - add(new BaseBlock(type)); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.masks; + +import java.util.Set; +import com.sk89q.worldedit.blocks.BaseBlock; + +/** + * A filter that matches blocks based on block types. + * + * @deprecated replaced by {@link #BlockMask} + * @author sk89q + */ +@Deprecated +public class BlockTypeMask extends BlockMask { + public BlockTypeMask() { + super(); + } + + public BlockTypeMask(Set types) { + super(); + for (int type : types) { + add(type); + } + } + + public BlockTypeMask(int type) { + this(); + add(type); + } + + public void add(int type) { + add(new BaseBlock(type)); + } +} diff --git a/src/main/java/com/sk89q/worldedit/masks/CombinedMask.java b/src/legacy/java/com/sk89q/worldedit/masks/CombinedMask.java similarity index 88% rename from src/main/java/com/sk89q/worldedit/masks/CombinedMask.java rename to src/legacy/java/com/sk89q/worldedit/masks/CombinedMask.java index fb12c8246..48b7c8d42 100644 --- a/src/main/java/com/sk89q/worldedit/masks/CombinedMask.java +++ b/src/legacy/java/com/sk89q/worldedit/masks/CombinedMask.java @@ -1,72 +1,84 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.masks; - -import java.util.ArrayList; -import java.util.List; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.Vector; - -public class CombinedMask extends AbstractMask { - private final List masks = new ArrayList(); - - public CombinedMask() { - } - - public CombinedMask(Mask mask) { - masks.add(mask); - } - - public CombinedMask(List masks) { - this.masks.addAll(masks); - } - - public void add(Mask mask) { - masks.add(mask); - } - - public boolean remove(Mask mask) { - return masks.remove(mask); - } - - public boolean has(Mask mask) { - return masks.contains(mask); - } - - @Override - public void prepare(LocalSession session, LocalPlayer player, Vector target) { - for (Mask mask : masks) { - mask.prepare(session, player, target); - } - } - - @Override - public boolean matches(EditSession editSession, Vector pos) { - for (Mask mask : masks) { - if (!mask.matches(editSession, pos)) { - return false; - } - } - - return true; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.masks; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.function.mask.MaskIntersection; + +import java.util.ArrayList; +import java.util.List; + +/** + * @deprecated See {@link MaskIntersection} + */ +@Deprecated +public class CombinedMask extends AbstractMask { + private final List masks = new ArrayList(); + + public CombinedMask() { + } + + public CombinedMask(Mask mask) { + add(mask); + } + + public CombinedMask(Mask ...mask) { + for (Mask m : mask) { + add(m); + } + } + + public CombinedMask(List masks) { + this.masks.addAll(masks); + } + + public void add(Mask mask) { + masks.add(mask); + } + + public boolean remove(Mask mask) { + return masks.remove(mask); + } + + public boolean has(Mask mask) { + return masks.contains(mask); + } + + @Override + public void prepare(LocalSession session, LocalPlayer player, Vector target) { + for (Mask mask : masks) { + mask.prepare(session, player, target); + } + } + + @Override + public boolean matches(EditSession editSession, Vector pos) { + for (Mask mask : masks) { + if (!mask.matches(editSession, pos)) { + return false; + } + } + + return true; + } +} diff --git a/src/main/java/com/sk89q/worldedit/masks/DynamicRegionMask.java b/src/legacy/java/com/sk89q/worldedit/masks/DynamicRegionMask.java similarity index 65% rename from src/main/java/com/sk89q/worldedit/masks/DynamicRegionMask.java rename to src/legacy/java/com/sk89q/worldedit/masks/DynamicRegionMask.java index bb4536df1..7c2b9438f 100644 --- a/src/main/java/com/sk89q/worldedit/masks/DynamicRegionMask.java +++ b/src/legacy/java/com/sk89q/worldedit/masks/DynamicRegionMask.java @@ -1,13 +1,14 @@ package com.sk89q.worldedit.masks; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.IncompleteRegionException; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.*; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.session.request.RequestSelection; -public class DynamicRegionMask implements Mask { +/** + * @deprecated Use {@link RequestSelection} with {@link com.sk89q.worldedit.function.mask.RegionMask} + */ +@Deprecated +public class DynamicRegionMask extends AbstractMask { private Region region; @Override diff --git a/src/main/java/com/sk89q/worldedit/masks/ExistingBlockMask.java b/src/legacy/java/com/sk89q/worldedit/masks/ExistingBlockMask.java similarity index 91% rename from src/main/java/com/sk89q/worldedit/masks/ExistingBlockMask.java rename to src/legacy/java/com/sk89q/worldedit/masks/ExistingBlockMask.java index ea9e8f448..c258314db 100644 --- a/src/main/java/com/sk89q/worldedit/masks/ExistingBlockMask.java +++ b/src/legacy/java/com/sk89q/worldedit/masks/ExistingBlockMask.java @@ -1,31 +1,35 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.masks; - -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.blocks.BlockID; - -public class ExistingBlockMask extends AbstractMask { - @Override - public boolean matches(EditSession editSession, Vector pos) { - return editSession.getBlockType(pos) != BlockID.AIR; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.masks; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BlockID; + +/** + * @deprecated See {@link com.sk89q.worldedit.function.mask.ExistingBlockMask} + */ +@Deprecated +public class ExistingBlockMask extends AbstractMask { + @Override + public boolean matches(EditSession editSession, Vector pos) { + return editSession.getBlockType(pos) != BlockID.AIR; + } +} diff --git a/src/legacy/java/com/sk89q/worldedit/masks/FuzzyBlockMask.java b/src/legacy/java/com/sk89q/worldedit/masks/FuzzyBlockMask.java new file mode 100644 index 000000000..e350802f8 --- /dev/null +++ b/src/legacy/java/com/sk89q/worldedit/masks/FuzzyBlockMask.java @@ -0,0 +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 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.masks; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; + +import java.util.HashSet; +import java.util.Set; + +/** + * @deprecated See {@link com.sk89q.worldedit.function.mask.FuzzyBlockMask} + */ +@Deprecated +public class FuzzyBlockMask extends AbstractMask { + + private final Set filter; + + /** + * Create a new fuzzy block mask. + * + * @param filter a list of block types to match + */ + public FuzzyBlockMask(Set filter) { + this.filter = filter; + } + + /** + * Create a new fuzzy block mask. + * + * @param block a list of block types to match + */ + public FuzzyBlockMask(BaseBlock... block) { + Set filter = new HashSet(); + for (BaseBlock b : block) { + filter.add(b); + } + this.filter = filter; + } + + @Override + public boolean matches(EditSession editSession, Vector pos) { + BaseBlock compare = new BaseBlock(editSession.getBlockType(pos), editSession.getBlockData(pos)); + return BaseBlock.containsFuzzy(filter, compare); + } +} diff --git a/src/main/java/com/sk89q/worldedit/masks/InvertedBlockTypeMask.java b/src/legacy/java/com/sk89q/worldedit/masks/InvertedBlockTypeMask.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/masks/InvertedBlockTypeMask.java rename to src/legacy/java/com/sk89q/worldedit/masks/InvertedBlockTypeMask.java index 9fef49649..da30fa917 100644 --- a/src/main/java/com/sk89q/worldedit/masks/InvertedBlockTypeMask.java +++ b/src/legacy/java/com/sk89q/worldedit/masks/InvertedBlockTypeMask.java @@ -1,54 +1,54 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.masks; - -import java.util.Set; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.Vector; - -/** - * A block type mask that only matches blocks that are not in the list. - * - * @author sk89q - */ -@Deprecated -public class InvertedBlockTypeMask extends BlockTypeMask { - public InvertedBlockTypeMask() { - } - - /** - * @param types - */ - public InvertedBlockTypeMask(Set types) { - super(types); - } - - /** - * @param type - */ - public InvertedBlockTypeMask(int type) { - super(type); - } - - @Override - public boolean matches(EditSession editSession, Vector pos) { - return !super.matches(editSession, pos); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.masks; + +import java.util.Set; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.Vector; + +/** + * A block type mask that only matches blocks that are not in the list. + * + * @author sk89q + */ +@Deprecated +public class InvertedBlockTypeMask extends BlockTypeMask { + public InvertedBlockTypeMask() { + } + + /** + * @param types + */ + public InvertedBlockTypeMask(Set types) { + super(types); + } + + /** + * @param type + */ + public InvertedBlockTypeMask(int type) { + super(type); + } + + @Override + public boolean matches(EditSession editSession, Vector pos) { + return !super.matches(editSession, pos); + } +} diff --git a/src/main/java/com/sk89q/worldedit/masks/InvertedMask.java b/src/legacy/java/com/sk89q/worldedit/masks/InvertedMask.java similarity index 82% rename from src/main/java/com/sk89q/worldedit/masks/InvertedMask.java rename to src/legacy/java/com/sk89q/worldedit/masks/InvertedMask.java index 9ffc5213e..b84113790 100644 --- a/src/main/java/com/sk89q/worldedit/masks/InvertedMask.java +++ b/src/legacy/java/com/sk89q/worldedit/masks/InvertedMask.java @@ -4,7 +4,12 @@ import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalPlayer; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.function.mask.Masks; +/** + * @deprecated See {@link Masks#negate(com.sk89q.worldedit.function.mask.Mask)} + */ +@Deprecated public class InvertedMask extends AbstractMask { private final Mask mask; diff --git a/src/main/java/com/sk89q/worldedit/masks/Mask.java b/src/legacy/java/com/sk89q/worldedit/masks/Mask.java similarity index 83% rename from src/main/java/com/sk89q/worldedit/masks/Mask.java rename to src/legacy/java/com/sk89q/worldedit/masks/Mask.java index d5a448736..0cca79f59 100644 --- a/src/main/java/com/sk89q/worldedit/masks/Mask.java +++ b/src/legacy/java/com/sk89q/worldedit/masks/Mask.java @@ -1,57 +1,53 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.masks; - -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.Vector; - -/** - * Base matcher for the block filtering framework. Implementing classes - * can be used to filter blocks to set or replace. - *

- * Do NOT implement this interface. Extend {@link AbstractMask} instead. - * - * @author sk89q - */ -public interface Mask { - - /** - * Called one time before each edit session. - * - * @param session - * @param player - * @param target target of the brush, null if not a brush mask - */ - void prepare(LocalSession session, LocalPlayer player, Vector target); - - /** - * Given a block position, this method returns true if the block at - * that position matches the filter. Block information is not provided - * as getting a BaseBlock has unneeded overhead in most block querying - * situations (enumerating a chest's contents is a waste, for example). - * - * @param editSession - * @param pos - * @return - */ - boolean matches(EditSession editSession, Vector pos); -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.masks; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.Vector; + +/** + * @deprecated Use {@link com.sk89q.worldedit.function.mask.Mask} + */ +@Deprecated +public interface Mask { + + /** + * Called one time before each edit session. + * + * @param session + * @param player + * @param target target of the brush, null if not a brush mask + */ + void prepare(LocalSession session, LocalPlayer player, Vector target); + + /** + * Given a block position, this method returns true if the block at + * that position matches the filter. Block information is not provided + * as getting a BaseBlock has unneeded overhead in most block querying + * situations (enumerating a chest's contents is a waste, for example). + * + * @param editSession + * @param pos + * @return + */ + boolean matches(EditSession editSession, Vector pos); +} diff --git a/src/main/java/com/sk89q/worldedit/masks/RandomMask.java b/src/legacy/java/com/sk89q/worldedit/masks/RandomMask.java similarity index 77% rename from src/main/java/com/sk89q/worldedit/masks/RandomMask.java rename to src/legacy/java/com/sk89q/worldedit/masks/RandomMask.java index 65c71af47..4b8374388 100644 --- a/src/main/java/com/sk89q/worldedit/masks/RandomMask.java +++ b/src/legacy/java/com/sk89q/worldedit/masks/RandomMask.java @@ -2,7 +2,12 @@ package com.sk89q.worldedit.masks; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.function.mask.NoiseFilter; +/** + * @deprecated See {@link NoiseFilter} + */ +@Deprecated public class RandomMask extends AbstractMask { private final double ratio; diff --git a/src/main/java/com/sk89q/worldedit/masks/RegionMask.java b/src/legacy/java/com/sk89q/worldedit/masks/RegionMask.java similarity index 92% rename from src/main/java/com/sk89q/worldedit/masks/RegionMask.java rename to src/legacy/java/com/sk89q/worldedit/masks/RegionMask.java index b734e7ae3..978f2fe54 100644 --- a/src/main/java/com/sk89q/worldedit/masks/RegionMask.java +++ b/src/legacy/java/com/sk89q/worldedit/masks/RegionMask.java @@ -1,37 +1,41 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.masks; - -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.regions.Region; - -public class RegionMask extends AbstractMask { - private final Region region; - - public RegionMask(Region region) { - this.region = region.clone(); - } - - @Override - public boolean matches(EditSession editSession, Vector pos) { - return region.contains(pos); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.masks; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.regions.Region; + +/** + * @deprecated See {@link com.sk89q.worldedit.function.mask.RegionMask} + */ +@Deprecated +public class RegionMask extends AbstractMask { + private final Region region; + + public RegionMask(Region region) { + this.region = region.clone(); + } + + @Override + public boolean matches(EditSession editSession, Vector pos) { + return region.contains(pos); + } +} diff --git a/src/main/java/com/sk89q/worldedit/masks/SolidBlockMask.java b/src/legacy/java/com/sk89q/worldedit/masks/SolidBlockMask.java similarity index 75% rename from src/main/java/com/sk89q/worldedit/masks/SolidBlockMask.java rename to src/legacy/java/com/sk89q/worldedit/masks/SolidBlockMask.java index f78170efc..c41f91e81 100644 --- a/src/main/java/com/sk89q/worldedit/masks/SolidBlockMask.java +++ b/src/legacy/java/com/sk89q/worldedit/masks/SolidBlockMask.java @@ -1,15 +1,16 @@ -package com.sk89q.worldedit.masks; - -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.blocks.BlockType; - -/** - * Works like {@link ExistingBlockMask}, except also dealing with non-solid non-air blocks the same way as with air. - */ -public class SolidBlockMask extends AbstractMask { - @Override - public boolean matches(EditSession editSession, Vector pos) { - return !BlockType.canPassThrough(editSession.getBlockType(pos), editSession.getBlockData(pos)); - } -} +package com.sk89q.worldedit.masks; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BlockType; + +/** + * @deprecated See {@link com.sk89q.worldedit.function.mask.SolidBlockMask} + */ +@Deprecated +public class SolidBlockMask extends AbstractMask { + @Override + public boolean matches(EditSession editSession, Vector pos) { + return !BlockType.canPassThrough(editSession.getBlockType(pos), editSession.getBlockData(pos)); + } +} diff --git a/src/main/java/com/sk89q/worldedit/masks/UnderOverlayMask.java b/src/legacy/java/com/sk89q/worldedit/masks/UnderOverlayMask.java similarity index 88% rename from src/main/java/com/sk89q/worldedit/masks/UnderOverlayMask.java rename to src/legacy/java/com/sk89q/worldedit/masks/UnderOverlayMask.java index 7c77a75da..154da7139 100644 --- a/src/main/java/com/sk89q/worldedit/masks/UnderOverlayMask.java +++ b/src/legacy/java/com/sk89q/worldedit/masks/UnderOverlayMask.java @@ -19,18 +19,21 @@ package com.sk89q.worldedit.masks; -import java.util.Set; - import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalPlayer; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.function.mask.MaskIntersection; +import com.sk89q.worldedit.function.mask.Masks; +import com.sk89q.worldedit.function.mask.OffsetMask; + +import java.util.Set; /** - * - * @author 1337 + * @deprecated Use {@link OffsetMask} with {@link MaskIntersection} and {@link Masks#negate(com.sk89q.worldedit.function.mask.Mask)} */ +@Deprecated public class UnderOverlayMask extends AbstractMask { private final int yMod; private Mask mask; diff --git a/src/main/java/com/sk89q/worldedit/patterns/BlockChance.java b/src/legacy/java/com/sk89q/worldedit/patterns/BlockChance.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/patterns/BlockChance.java rename to src/legacy/java/com/sk89q/worldedit/patterns/BlockChance.java index b8427ae32..a51cacf29 100644 --- a/src/main/java/com/sk89q/worldedit/patterns/BlockChance.java +++ b/src/legacy/java/com/sk89q/worldedit/patterns/BlockChance.java @@ -22,10 +22,9 @@ package com.sk89q.worldedit.patterns; import com.sk89q.worldedit.blocks.BaseBlock; /** - * Gives a block a chance. - * - * @author sk89q + * @deprecated Will be removed in the future -- there is no replacement */ +@Deprecated public class BlockChance { /** * Block. diff --git a/src/main/java/com/sk89q/worldedit/patterns/ClipboardPattern.java b/src/legacy/java/com/sk89q/worldedit/patterns/ClipboardPattern.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/patterns/ClipboardPattern.java rename to src/legacy/java/com/sk89q/worldedit/patterns/ClipboardPattern.java index cbef1935e..2efaf4601 100644 --- a/src/main/java/com/sk89q/worldedit/patterns/ClipboardPattern.java +++ b/src/legacy/java/com/sk89q/worldedit/patterns/ClipboardPattern.java @@ -1,75 +1,75 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.patterns; - -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.blocks.BaseBlock; - -/** - * Pattern that repeats the clipboard. - * - * @author sk89q - */ -public class ClipboardPattern implements Pattern { - /** - * Clipboard. - */ - private CuboidClipboard clipboard; - /** - * Size of the clipboard. - */ - private Vector size; - - /** - * Construct the object. - * - * @param clipboard - */ - public ClipboardPattern(CuboidClipboard clipboard) { - this.clipboard = clipboard; - this.size = clipboard.getSize(); - } - - /** - * Get next block. - * - * @param pos - * @return - */ - public BaseBlock next(Vector pos) { - return next(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); - } - - /** - * Get next block. - * - * @param x - * @param y - * @param z - * @return - */ - public BaseBlock next(int x, int y, int z) { - int xp = Math.abs(x) % size.getBlockX(); - int yp = Math.abs(y) % size.getBlockY(); - int zp = Math.abs(z) % size.getBlockZ(); - - return clipboard.getPoint(new Vector(xp, yp, zp)); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.patterns; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.blocks.BaseBlock; + +/** + * Pattern that repeats the clipboard. + * + * @author sk89q + */ +public class ClipboardPattern implements Pattern { + /** + * Clipboard. + */ + private CuboidClipboard clipboard; + /** + * Size of the clipboard. + */ + private Vector size; + + /** + * Construct the object. + * + * @param clipboard + */ + public ClipboardPattern(CuboidClipboard clipboard) { + this.clipboard = clipboard; + this.size = clipboard.getSize(); + } + + /** + * Get next block. + * + * @param pos + * @return + */ + public BaseBlock next(Vector pos) { + return next(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); + } + + /** + * Get next block. + * + * @param x + * @param y + * @param z + * @return + */ + public BaseBlock next(int x, int y, int z) { + int xp = Math.abs(x) % size.getBlockX(); + int yp = Math.abs(y) % size.getBlockY(); + int zp = Math.abs(z) % size.getBlockZ(); + + return clipboard.getPoint(new Vector(xp, yp, zp)); + } +} diff --git a/src/main/java/com/sk89q/worldedit/patterns/Pattern.java b/src/legacy/java/com/sk89q/worldedit/patterns/Pattern.java similarity index 90% rename from src/main/java/com/sk89q/worldedit/patterns/Pattern.java rename to src/legacy/java/com/sk89q/worldedit/patterns/Pattern.java index d1ec4a25e..eb2b9f2dc 100644 --- a/src/main/java/com/sk89q/worldedit/patterns/Pattern.java +++ b/src/legacy/java/com/sk89q/worldedit/patterns/Pattern.java @@ -23,11 +23,9 @@ import com.sk89q.worldedit.*; import com.sk89q.worldedit.blocks.BaseBlock; /** - * Used to get the block to set. This can be used to implement a pattern - * for when setting a region with blocks. - * - * @author sk89q + * @deprecated See {@link com.sk89q.worldedit.function.pattern.Pattern} */ +@Deprecated public interface Pattern { /** * Get a block for a position. This return value of this method does diff --git a/src/main/java/com/sk89q/worldedit/patterns/RandomFillPattern.java b/src/legacy/java/com/sk89q/worldedit/patterns/RandomFillPattern.java similarity index 93% rename from src/main/java/com/sk89q/worldedit/patterns/RandomFillPattern.java rename to src/legacy/java/com/sk89q/worldedit/patterns/RandomFillPattern.java index 5217e4a9e..e322798ba 100644 --- a/src/main/java/com/sk89q/worldedit/patterns/RandomFillPattern.java +++ b/src/legacy/java/com/sk89q/worldedit/patterns/RandomFillPattern.java @@ -19,17 +19,18 @@ package com.sk89q.worldedit.patterns; -import java.util.Random; -import java.util.List; -import java.util.ArrayList; -import com.sk89q.worldedit.*; +import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.function.pattern.RandomPattern; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; /** - * Pattern proportionally fills. - * - * @author sk89q + * @deprecated See {@link RandomPattern} */ +@Deprecated public class RandomFillPattern implements Pattern { /** * Random number generator. diff --git a/src/main/java/com/sk89q/worldedit/patterns/SingleBlockPattern.java b/src/legacy/java/com/sk89q/worldedit/patterns/SingleBlockPattern.java similarity index 93% rename from src/main/java/com/sk89q/worldedit/patterns/SingleBlockPattern.java rename to src/legacy/java/com/sk89q/worldedit/patterns/SingleBlockPattern.java index f518f8de1..94457610d 100644 --- a/src/main/java/com/sk89q/worldedit/patterns/SingleBlockPattern.java +++ b/src/legacy/java/com/sk89q/worldedit/patterns/SingleBlockPattern.java @@ -21,12 +21,12 @@ package com.sk89q.worldedit.patterns; import com.sk89q.worldedit.*; import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.function.pattern.BlockPattern; /** - * Always returns the same block type. - * - * @author sk89q + * @deprecated See {@link BlockPattern} */ +@Deprecated public class SingleBlockPattern implements Pattern { /** * Block type. diff --git a/src/main/java/com/sk89q/jnbt/NBTUtils.java b/src/main/java/com/sk89q/jnbt/NBTUtils.java index 21057a1ec..da1a944c4 100644 --- a/src/main/java/com/sk89q/jnbt/NBTUtils.java +++ b/src/main/java/com/sk89q/jnbt/NBTUtils.java @@ -2,20 +2,7 @@ package com.sk89q.jnbt; import java.util.Map; -import com.sk89q.jnbt.ByteArrayTag; -import com.sk89q.jnbt.ByteTag; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.DoubleTag; -import com.sk89q.jnbt.EndTag; -import com.sk89q.jnbt.FloatTag; -import com.sk89q.jnbt.IntTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.LongTag; -import com.sk89q.jnbt.NBTConstants; -import com.sk89q.jnbt.ShortTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.data.InvalidFormatException; +import com.sk89q.worldedit.world.storage.InvalidFormatException; /* * JNBT License diff --git a/src/main/java/com/sk89q/worldedit/CuboidClipboard.java b/src/main/java/com/sk89q/worldedit/CuboidClipboard.java index 6f3bddc23..66d2acce4 100644 --- a/src/main/java/com/sk89q/worldedit/CuboidClipboard.java +++ b/src/main/java/com/sk89q/worldedit/CuboidClipboard.java @@ -30,9 +30,10 @@ import java.util.Map; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BlockID; -import com.sk89q.worldedit.data.DataException; +import com.sk89q.worldedit.world.DataException; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.schematic.SchematicFormat; +import com.sk89q.worldedit.util.Countable; /** * The clipboard remembers the state of a cuboid region. diff --git a/src/main/java/com/sk89q/worldedit/EditSession.java b/src/main/java/com/sk89q/worldedit/EditSession.java index f07c45ac8..3881267ab 100644 --- a/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/src/main/java/com/sk89q/worldedit/EditSession.java @@ -1,7 +1,7 @@ -// $Id$ /* - * WorldEditLibrary - * Copyright (C) 2010 sk89q and contributors + * 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 @@ -16,454 +16,196 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + package com.sk89q.worldedit; -import com.sk89q.worldedit.bags.BlockBag; -import com.sk89q.worldedit.bags.BlockBagException; -import com.sk89q.worldedit.bags.UnplaceableBlockException; +import com.sk89q.worldedit.extent.buffer.ForgetfulExtentBuffer; +import com.sk89q.worldedit.extent.cache.LastAccessExtentCache; +import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BlockID; import com.sk89q.worldedit.blocks.BlockType; -import com.sk89q.worldedit.expression.Expression; -import com.sk89q.worldedit.expression.ExpressionException; -import com.sk89q.worldedit.expression.runtime.RValue; -import com.sk89q.worldedit.generator.ForestGenerator; -import com.sk89q.worldedit.generator.GardenPatchGenerator; -import com.sk89q.worldedit.operation.GroundScatterFunction; -import com.sk89q.worldedit.interpolation.Interpolation; -import com.sk89q.worldedit.interpolation.KochanekBartelsInterpolation; -import com.sk89q.worldedit.interpolation.Node; +import com.sk89q.worldedit.event.extent.EditSessionEvent; +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.ExpressionException; +import com.sk89q.worldedit.internal.expression.runtime.RValue; +import com.sk89q.worldedit.extent.*; +import com.sk89q.worldedit.extent.inventory.BlockBagExtent; +import com.sk89q.worldedit.extent.reorder.MultiStageReorder; +import com.sk89q.worldedit.extent.validation.BlockChangeLimiter; +import com.sk89q.worldedit.extent.validation.DataValidatorExtent; +import com.sk89q.worldedit.extent.world.BlockQuirkExtent; +import com.sk89q.worldedit.extent.world.ChunkLoadingExtent; +import com.sk89q.worldedit.extent.world.FastModeExtent; +import com.sk89q.worldedit.function.GroundFunction; +import com.sk89q.worldedit.function.RegionMaskingFilter; +import com.sk89q.worldedit.function.block.Counter; +import com.sk89q.worldedit.function.block.BlockReplace; +import com.sk89q.worldedit.function.block.Naturalizer; +import com.sk89q.worldedit.function.generator.GardenPatchGenerator; +import com.sk89q.worldedit.function.mask.*; +import com.sk89q.worldedit.function.operation.*; +import com.sk89q.worldedit.function.pattern.BlockPattern; +import com.sk89q.worldedit.function.pattern.Patterns; +import com.sk89q.worldedit.function.util.RegionOffset; +import com.sk89q.worldedit.function.visitor.*; +import com.sk89q.worldedit.history.UndoContext; +import com.sk89q.worldedit.history.change.BlockChange; +import com.sk89q.worldedit.history.changeset.BlockOptimizedHistory; +import com.sk89q.worldedit.history.changeset.ChangeSet; import com.sk89q.worldedit.masks.Mask; -import com.sk89q.worldedit.operation.FlatRegionApplicator; -import com.sk89q.worldedit.operation.OperationHelper; +import com.sk89q.worldedit.math.interpolation.Interpolation; +import com.sk89q.worldedit.math.interpolation.KochanekBartelsInterpolation; +import com.sk89q.worldedit.math.interpolation.Node; +import com.sk89q.worldedit.math.noise.RandomNoise; +import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.patterns.Pattern; -import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.regions.RegionOperationException; -import com.sk89q.worldedit.shape.ArbitraryBiomeShape; -import com.sk89q.worldedit.shape.ArbitraryShape; -import com.sk89q.worldedit.shape.RegionShape; -import com.sk89q.worldedit.shape.WorldEditExpressionEnvironment; +import com.sk89q.worldedit.patterns.SingleBlockPattern; +import com.sk89q.worldedit.regions.*; +import com.sk89q.worldedit.regions.shape.ArbitraryBiomeShape; +import com.sk89q.worldedit.regions.shape.ArbitraryShape; +import com.sk89q.worldedit.regions.shape.RegionShape; +import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment; +import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.TreeGenerator; +import com.sk89q.worldedit.util.collection.DoubleArrayList; +import com.sk89q.worldedit.util.eventbus.EventBus; +import javax.annotation.Nullable; import java.util.*; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.regions.Regions.*; + /** - * This class can wrap all block editing operations into one "edit session" that - * stores the state of the blocks before modification. This allows for easy undo - * or redo. In addition to that, this class can use a "queue mode" that will - * know how to handle some special types of items such as signs and torches. For - * example, torches must be placed only after there is already a block below it, - * otherwise the torch will be placed as an item. - * - * @author sk89q + * An {@link Extent} that handles history, {@link BlockBag}s, change limits, + * block re-ordering, and much more. Most operations in WorldEdit use this class. + *

+ * Most of the actual functionality is implemented with a number of other + * {@link Extent}s that are chained together. For example, history is logged + * using the {@link ChangeSetExtent}. */ -public class EditSession { +@SuppressWarnings("FieldCanBeLocal") +public class EditSession implements Extent { /** - * Random number generator. + * Used by {@link #setBlock(Vector, BaseBlock, Stage)} to + * determine which {@link Extent}s should be bypassed. */ - private static Random prng = new Random(); - - /** - * World. - */ - protected LocalWorld world; - - /** - * Stores the original blocks before modification. - */ - private DoubleArrayList original = - new DoubleArrayList(true); - - /** - * Stores the current blocks. - */ - private DoubleArrayList current = - new DoubleArrayList(false); - - /** - * Blocks that should be placed before last. - */ - private DoubleArrayList queueAfter = - new DoubleArrayList(false); - - /** - * Blocks that should be placed last. - */ - private DoubleArrayList queueLast = - new DoubleArrayList(false); - - /** - * Blocks that should be placed after all other blocks. - */ - private DoubleArrayList queueFinal = - new DoubleArrayList(false); - - /** - * The maximum number of blocks to change at a time. If this number is - * exceeded, a MaxChangedBlocksException exception will be raised. -1 - * indicates no limit. - */ - private int maxBlocks = -1; - - /** - * Indicates whether some types of blocks should be queued for best - * reproduction. - */ - private boolean queued = false; - - /** - * Use the fast mode, which may leave chunks not flagged "dirty". - */ - private boolean fastMode = false; - - /** - * Block bag to use for getting blocks. - */ - private BlockBag blockBag; - - /** - * List of missing blocks; - */ - private Map missingBlocks = new HashMap(); - - /** - * Mask to cover operations. - */ - private Mask mask; - - /** - * Construct the object with a maximum number of blocks. - * - * @param world - * @param maxBlocks - */ - public EditSession(LocalWorld world, int maxBlocks) { - if (maxBlocks < -1) { - throw new IllegalArgumentException("Max blocks must be >= -1"); - } - - this.maxBlocks = maxBlocks; - this.world = world; + public enum Stage { + BEFORE_HISTORY, + BEFORE_REORDER, + BEFORE_CHANGE } + @SuppressWarnings("ProtectedField") + protected final LocalWorld world; + private final ChangeSet changeSet = new BlockOptimizedHistory(); + + private final FastModeExtent fastModeExtent; + private final ChunkLoadingExtent chunkLoadingExtent; + private final LastAccessExtentCache cacheExtent; + private final BlockQuirkExtent quirkExtent; + private final DataValidatorExtent validator; + private final BlockBagExtent blockBagExtent; + private final MultiStageReorder reorderExtent; + private final ChangeSetExtent changeSetExtent; + private final MaskingExtent maskingExtent; + private final BlockChangeLimiter changeLimiter; + + private final Extent bypassReorderHistory; + private final Extent bypassHistory; + private final Extent bypassNone; + + @SuppressWarnings("deprecation") + private Mask oldMask; + /** * Construct the object with a maximum number of blocks and a block bag. * - * @param world - * @param maxBlocks - * @param blockBag - * @blockBag + * @param eventBus the event bus + * @param world the world + * @param maxBlocks the maximum number of blocks that can be changed, or -1 to use no limit + * @param blockBag an optional {@link BlockBag} to use, otherwise null + * @param event the event to call with the extent */ - public EditSession(LocalWorld world, int maxBlocks, BlockBag blockBag) { - if (maxBlocks < -1) { - throw new IllegalArgumentException("Max blocks must be >= -1"); - } + public EditSession(EventBus eventBus, LocalWorld world, int maxBlocks, @Nullable BlockBag blockBag, EditSessionEvent event) { + checkNotNull(eventBus); + checkNotNull(world); + checkArgument(maxBlocks >= -1, "maxBlocks >= -1 required"); + checkNotNull(event); - this.maxBlocks = maxBlocks; - this.blockBag = blockBag; this.world = world; + + Extent extent; + + // This extents are ALWAYS used + extent = fastModeExtent = new FastModeExtent(world, false); + extent = chunkLoadingExtent = new ChunkLoadingExtent(extent, world); + extent = cacheExtent = new LastAccessExtentCache(extent); + extent = wrapExtent(extent, eventBus, event, Stage.BEFORE_CHANGE); + extent = quirkExtent = new BlockQuirkExtent(extent, world); + extent = validator = new DataValidatorExtent(extent, world); + extent = blockBagExtent = new BlockBagExtent(extent, world, blockBag); + + // This extent can be skipped by calling rawSetBlock() + extent = reorderExtent = new MultiStageReorder(extent, false); + extent = wrapExtent(extent, eventBus, event, Stage.BEFORE_REORDER); + + // These extents can be skipped by calling smartSetBlock() + extent = changeSetExtent = new ChangeSetExtent(extent, changeSet); + extent = maskingExtent = new MaskingExtent(extent, Masks.alwaysTrue()); + extent = changeLimiter = new BlockChangeLimiter(extent, maxBlocks); + extent = wrapExtent(extent, eventBus, event, Stage.BEFORE_HISTORY); + + this.bypassReorderHistory = blockBagExtent; + this.bypassHistory = reorderExtent; + this.bypassNone = extent; + } + + private Extent wrapExtent(Extent extent, EventBus eventBus, EditSessionEvent event, Stage stage) { + event = event.clone(stage); + event.setExtent(extent); + eventBus.post(event); + return event.getExtent(); } /** - * Sets a block without changing history. + * Get the world. * - * @param pt - * @param block - * @return Whether the block changed + * @return the world */ - public boolean rawSetBlock(Vector pt, BaseBlock block) { - final int y = pt.getBlockY(); - final int type = block.getType(); - if (y < 0 || y > world.getMaxY()) { - return false; - } - - world.checkLoadedChunk(pt); - - // No invalid blocks - if (!world.isValidBlockType(type)) { - return false; - } - - final int existing = world.getBlockType(pt); - - // Clear the container block so that it doesn't drop items - if (BlockType.isContainerBlock(existing)) { - world.clearContainerBlockContents(pt); - // Ice turns until water so this has to be done first - } else if (existing == BlockID.ICE) { - world.setBlockType(pt, BlockID.AIR); - } - - if (blockBag != null) { - if (type > 0) { - try { - blockBag.fetchPlacedBlock(type, 0); - } catch (UnplaceableBlockException e) { - return false; - } catch (BlockBagException e) { - if (!missingBlocks.containsKey(type)) { - missingBlocks.put(type, 1); - } else { - missingBlocks.put(type, missingBlocks.get(type) + 1); - } - return false; - } - } - - if (existing > 0) { - try { - blockBag.storeDroppedBlock(existing, world.getBlockData(pt)); - } catch (BlockBagException e) { - } - } - } - - boolean result; - - if (type == 0) { - if (fastMode) { - result = world.setBlockTypeFast(pt, 0); - } else { - result = world.setBlockType(pt, 0); - } - } else { - result = world.setBlock(pt, block, !fastMode); - } - - return result; + public LocalWorld getWorld() { + return world; } /** - * Sets the block at position x, y, z with a block type. If queue mode is - * enabled, blocks may not be actually set in world until flushQueue() is - * called. + * Get the underlying {@link ChangeSet}. * - * @param pt - * @param block - * @return Whether the block changed -- not entirely dependable - * @throws MaxChangedBlocksException + * @return the change set */ - public boolean setBlock(Vector pt, BaseBlock block) - throws MaxChangedBlocksException { - BlockVector blockPt = pt.toBlockVector(); - - if (mask != null) { - if (!mask.matches(this, blockPt)) { - return false; - } - } - - // if (!original.containsKey(blockPt)) { - original.put(blockPt, getBlock(pt)); - - if (maxBlocks != -1 && original.size() > maxBlocks) { - throw new MaxChangedBlocksException(maxBlocks); - } - // } - - current.put(blockPt, block); - - return smartSetBlock(pt, block); - } - - /** - * Insert a contrived block change into the history. - * - * @param pt - * @param existing - * @param block - */ - public void rememberChange(Vector pt, BaseBlock existing, BaseBlock block) { - BlockVector blockPt = pt.toBlockVector(); - - original.put(blockPt, existing); - current.put(pt.toBlockVector(), block); - } - - /** - * Set a block with a pattern. - * - * @param pt - * @param pat - * @return Whether the block changed -- not entirely dependable - * @throws MaxChangedBlocksException - */ - public boolean setBlock(Vector pt, Pattern pat) - throws MaxChangedBlocksException { - return setBlock(pt, pat.next(pt)); - } - - /** - * Set a block only if there's no block already there. - * - * @param pt - * @param block - * @return if block was changed - * @throws MaxChangedBlocksException - */ - public boolean setBlockIfAir(Vector pt, BaseBlock block) - throws MaxChangedBlocksException { - if (!getBlock(pt).isAir()) { - return false; - } else { - return setBlock(pt, block); - } - } - - /** - * Actually set the block. Will use queue. - * - * @param pt - * @param block - * @return - */ - public boolean smartSetBlock(Vector pt, BaseBlock block) { - if (queued) { - if (BlockType.shouldPlaceLast(block.getType())) { - // Place torches, etc. last - queueLast.put(pt.toBlockVector(), block); - return !(getBlockType(pt) == block.getType() && getBlockData(pt) == block.getData()); - } else if (BlockType.shouldPlaceFinal(block.getType())) { - // Place signs, reed, etc even later - queueFinal.put(pt.toBlockVector(), block); - return !(getBlockType(pt) == block.getType() && getBlockData(pt) == block.getData()); - } else if (BlockType.shouldPlaceLast(getBlockType(pt))) { - // Destroy torches, etc. first - rawSetBlock(pt, new BaseBlock(BlockID.AIR)); - } else { - queueAfter.put(pt.toBlockVector(), block); - return !(getBlockType(pt) == block.getType() && getBlockData(pt) == block.getData()); - } - } - - return rawSetBlock(pt, block); - } - - /** - * Gets the block type at a position x, y, z. - * - * @param pt - * @return Block type - */ - public BaseBlock getBlock(Vector pt) { - // In the case of the queue, the block may have not actually been - // changed yet - if (queued) { - /* - * BlockVector blockPt = pt.toBlockVector(); - * - * if (current.containsKey(blockPt)) { return current.get(blockPt); - * } - */ - } - - return rawGetBlock(pt); - } - - /** - * Gets the block type at a position x, y, z. - * - * @param pt - * @return Block type - */ - public int getBlockType(Vector pt) { - // In the case of the queue, the block may have not actually been - // changed yet - if (queued) { - /* - * BlockVector blockPt = pt.toBlockVector(); - * - * if (current.containsKey(blockPt)) { return current.get(blockPt); - * } - */ - } - - return world.getBlockType(pt); - } - - public int getBlockData(Vector pt) { - // In the case of the queue, the block may have not actually been - // changed yet - if (queued) { - /* - * BlockVector blockPt = pt.toBlockVector(); - * - * if (current.containsKey(blockPt)) { return current.get(blockPt); - * } - */ - } - - return world.getBlockData(pt); - } - - /** - * Gets the block type at a position x, y, z. - * - * @param pt - * @return BaseBlock - */ - public BaseBlock rawGetBlock(Vector pt) { - return world.getBlock(pt); - } - - /** - * Restores all blocks to their initial state. - * - * @param sess - */ - public void undo(EditSession sess) { - for (Map.Entry entry : original) { - BlockVector pt = entry.getKey(); - sess.smartSetBlock(pt, entry.getValue()); - } - sess.flushQueue(); - } - - /** - * Sets to new state. - * - * @param sess - */ - public void redo(EditSession sess) { - for (Map.Entry entry : current) { - BlockVector pt = entry.getKey(); - sess.smartSetBlock(pt, entry.getValue()); - } - sess.flushQueue(); - } - - /** - * Get the number of changed blocks. - * - * @return - */ - public int size() { - return original.size(); + public ChangeSet getChangeSet() { + return changeSet; } /** * Get the maximum number of blocks that can be changed. -1 will be returned - * if disabled. + * if it the limit disabled. * - * @return block change limit + * @return the limit (>= 0) or -1 for no limit */ public int getBlockChangeLimit() { - return maxBlocks; + return changeLimiter.getLimit(); } /** * Set the maximum number of blocks that can be changed. * - * @param maxBlocks -1 to disable + * @param limit the limit (>= 0) or -1 for no limit */ - public void setBlockChangeLimit(int maxBlocks) { - if (maxBlocks < -1) { - throw new IllegalArgumentException("Max blocks must be >= -1"); - } - this.maxBlocks = maxBlocks; + public void setBlockChangeLimit(int limit) { + changeLimiter.setLimit(limit); } /** @@ -472,120 +214,163 @@ public class EditSession { * @return whether the queue is enabled */ public boolean isQueueEnabled() { - return queued; + return reorderExtent.isEnabled(); } /** * Queue certain types of block for better reproduction of those blocks. */ public void enableQueue() { - queued = true; + reorderExtent.setEnabled(true); } /** * Disable the queue. This will flush the queue. */ public void disableQueue() { - if (queued) { + if (isQueueEnabled()) { flushQueue(); } - queued = false; + reorderExtent.setEnabled(true); } /** - * Set fast mode. + * Get the mask. * - * @param fastMode + * @return mask, may be null */ - public void setFastMode(boolean fastMode) { - this.fastMode = fastMode; + @SuppressWarnings("deprecation") + public Mask getMask() { + return oldMask; + } + + /** + * Set a mask. + * + * @param mask mask or null + */ + @SuppressWarnings("deprecation") + public void setMask(Mask mask) { + this.oldMask = mask; + if (mask == null) { + maskingExtent.setMask(Masks.alwaysTrue()); + } else { + maskingExtent.setMask(Masks.wrap(mask, this)); + } + } + + /** + * Set whether fast mode is enabled. + *

+ * Fast mode may skip lighting checks or adjacent block notification. + * + * @param enabled true to enable + */ + public void setFastMode(boolean enabled) { + fastModeExtent.setEnabled(enabled); } /** * Return fast mode status. + *

+ * Fast mode may skip lighting checks or adjacent block notification. * - * @return + * @return true if enabled */ public boolean hasFastMode() { - return fastMode; + return fastModeExtent.isEnabled(); } /** - * Set a block by chance. + * Get the {@link BlockBag} is used. * - * @param pos - * @param block - * @param c 0-1 chance - * @return whether a block was changed - * @throws MaxChangedBlocksException + * @return a block bag or null */ - public boolean setChanceBlockIfAir(Vector pos, BaseBlock block, double c) - throws MaxChangedBlocksException { - if (Math.random() <= c) { - return setBlockIfAir(pos, block); - } - return false; - } - - public int countBlock(Region region, Set searchIDs) { - Set passOn = new HashSet(); - for (Integer i : searchIDs) { - passOn.add(new BaseBlock(i, -1)); - } - return countBlocks(region, passOn); + public BlockBag getBlockBag() { + return blockBagExtent.getBlockBag(); } /** - * Count the number of blocks of a list of types in a region. + * Set a {@link BlockBag} to use. * - * @param region - * @param searchBlocks - * @return + * @param blockBag the block bag to set, or null to use none */ - public int countBlocks(Region region, Set searchBlocks) { - int count = 0; + public void setBlockBag(BlockBag blockBag) { + blockBagExtent.setBlockBag(blockBag); + } - if (region instanceof CuboidRegion) { - // Doing this for speed - Vector min = region.getMinimumPoint(); - Vector max = region.getMaximumPoint(); + /** + * Gets the list of missing blocks and clears the list for the next + * operation. + * + * @return a map of missing blocks + */ + public Map popMissingBlocks() { + return blockBagExtent.popMissing(); + } - int minX = min.getBlockX(); - int minY = min.getBlockY(); - int minZ = min.getBlockZ(); - int maxX = max.getBlockX(); - int maxY = max.getBlockY(); - int maxZ = max.getBlockZ(); + /** + * Get the number of blocks changed, including repeated block changes. + *

+ * This number may not be accurate. + * + * @return the number of block changes + */ + public int getBlockChangeCount() { + return changeSet.size(); + } - for (int x = minX; x <= maxX; ++x) { - for (int y = minY; y <= maxY; ++y) { - for (int z = minZ; z <= maxZ; ++z) { - Vector pt = new Vector(x, y, z); + @Override + public BaseBlock getLazyBlock(Vector position) { + return world.getLazyBlock(position); + } - BaseBlock compare = new BaseBlock(getBlockType(pt), getBlockData(pt)); - if (BaseBlock.containsFuzzy(searchBlocks, compare)) { - ++count; - } - } - } - } - } else { - for (Vector pt : region) { - BaseBlock compare = new BaseBlock(getBlockType(pt), getBlockData(pt)); - if (BaseBlock.containsFuzzy(searchBlocks, compare)) { - ++count; - } - } - } + @Override + public BaseBlock getBlock(Vector position) { + return world.getBlock(position); + } - return count; + /** + * Get a block type at the given position. + * + * @param position the position + * @return the block type + * @deprecated Use {@link #getLazyBlock(Vector)} or {@link #getBlock(Vector)} + */ + @Deprecated + public int getBlockType(Vector position) { + return world.getBlockType(position); + } + + /** + * Get a block data at the given position. + * + * @param position the position + * @return the block data + * @deprecated Use {@link #getLazyBlock(Vector)} or {@link #getBlock(Vector)} + */ + @Deprecated + public int getBlockData(Vector position) { + return world.getBlockData(position); + } + + /** + * Gets the block type at a position. + * + * @param position the position + * @return a block + * @deprecated Use {@link #getBlock(Vector)} + */ + @Deprecated + public BaseBlock rawGetBlock(Vector position) { + return getBlock(position); } /** * Returns the highest solid 'terrain' block which can occur naturally. * - * @param x - * @param z + * @param x the X coordinate + * @param z the Z cooridnate * @param minY minimal height * @param maxY maximal height * @return height of highest block found or 'minY' @@ -597,8 +382,8 @@ public class EditSession { /** * Returns the highest solid 'terrain' block which can occur naturally. * - * @param x - * @param z + * @param x the X coordinate + * @param z the Z coordinate * @param minY minimal height * @param maxY maximal height * @param naturalOnly look at natural blocks or all blocks @@ -613,1510 +398,807 @@ public class EditSession { return y; } } + return minY; } /** - * Gets the list of missing blocks and clears the list for the next - * operation. + * Set a block, bypassing both history and block re-ordering. * - * @return + * @param position the position to set the block at + * @param block the block + * @param stage the level + * @return whether the block changed */ - public Map popMissingBlocks() { - Map missingBlocks = this.missingBlocks; - this.missingBlocks = new HashMap(); - return missingBlocks; + public boolean setBlock(Vector position, BaseBlock block, Stage stage) throws WorldEditException { + switch (stage) { + case BEFORE_HISTORY: + return bypassNone.setBlock(position, block); + case BEFORE_CHANGE: + return bypassHistory.setBlock(position, block); + case BEFORE_REORDER: + return bypassReorderHistory.setBlock(position, block); + } + + throw new RuntimeException("New enum entry added that is unhandled here"); } /** - * @return the blockBag - */ - public BlockBag getBlockBag() { - return blockBag; - } - - /** - * @param blockBag the blockBag to set - */ - public void setBlockBag(BlockBag blockBag) { - this.blockBag = blockBag; - } - - /** - * Get the world. + * Set a block, bypassing both history and block re-ordering. * - * @return + * @param position the position to set the block at + * @param block the block + * @return whether the block changed */ - public LocalWorld getWorld() { - return world; + public boolean rawSetBlock(Vector position, BaseBlock block) { + try { + return setBlock(position, block, Stage.BEFORE_CHANGE); + } catch (WorldEditException e) { + throw new RuntimeException("Unexpected exception", e); + } } /** - * Get the number of blocks changed, including repeated block changes. + * Set a block, bypassing history but still utilizing block re-ordering. * - * @return + * @param position the position to set the block at + * @param block the block + * @return whether the block changed */ - public int getBlockChangeCount() { - return original.size(); + public boolean smartSetBlock(Vector position, BaseBlock block) { + try { + return setBlock(position, block, Stage.BEFORE_REORDER); + } catch (WorldEditException e) { + throw new RuntimeException("Unexpected exception", e); + } + } + + @Override + public boolean setBlock(Vector position, BaseBlock block) throws MaxChangedBlocksException { + try { + return setBlock(position, block, Stage.BEFORE_HISTORY); + } catch (MaxChangedBlocksException e) { + throw e; + } catch (WorldEditException e) { + throw new RuntimeException("Unexpected exception", e); + } } /** - * Get the mask. + * Sets the block at a position, subject to both history and block re-ordering. * - * @return mask, may be null + * @param position the position + * @param pattern a pattern to use + * @return Whether the block changed -- not entirely dependable + * @throws MaxChangedBlocksException thrown if too many blocks are changed */ - public Mask getMask() { - return mask; + @SuppressWarnings("deprecation") + public boolean setBlock(Vector position, Pattern pattern) throws MaxChangedBlocksException { + return setBlock(position, pattern.next(position)); } /** - * Set a mask. + * Set blocks that are in a set of positions and return the number of times + * that the block set calls returned true. * - * @param mask mask or null + * @param vset a set of positions + * @param pattern the pattern + * @return the number of changed blocks + * @throws MaxChangedBlocksException thrown if too many blocks are changed */ - public void setMask(Mask mask) { - this.mask = mask; + @SuppressWarnings("deprecation") + private int setBlocks(Set vset, Pattern pattern) throws MaxChangedBlocksException { + int affected = 0; + for (Vector v : vset) { + affected += setBlock(v, pattern) ? 1 : 0; + } + return affected; + } + + /** + * 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 + */ + @SuppressWarnings("deprecation") + public boolean setChanceBlockIfAir(Vector position, BaseBlock block, double probability) + throws MaxChangedBlocksException { + return Math.random() <= probability && setBlockIfAir(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 + * @deprecated Use your own method + */ + @Deprecated + public boolean setBlockIfAir(Vector position, BaseBlock block) throws MaxChangedBlocksException { + return getBlock(position).isAir() && setBlock(position, block); + } + + /** + * Insert a contrived block change into the history. + * + * @param position the position + * @param existing the previous block at that position + * @param block the new block + * @deprecated Get the change set with {@link #getChangeSet()} and add the change with that + */ + @Deprecated + public void rememberChange(Vector position, BaseBlock existing, BaseBlock block) { + changeSet.add(new BlockChange(position.toBlockVector(), existing, block)); + } + + /** + * Restores all blocks to their initial state. + * + * @param editSession a new {@link EditSession} to perform the undo in + */ + public void undo(EditSession editSession) { + UndoContext context = new UndoContext(); + context.setExtent(editSession.bypassHistory); + Operations.completeBlindly(ChangeSetExecutor.createUndo(changeSet, context)); + editSession.flushQueue(); + } + + /** + * Sets to new state. + * + * @param editSession a new {@link EditSession} to perform the redo in + */ + public void redo(EditSession editSession) { + UndoContext context = new UndoContext(); + context.setExtent(editSession.bypassHistory); + Operations.completeBlindly(ChangeSetExecutor.createRedo(changeSet, context)); + editSession.flushQueue(); + } + + /** + * Get the number of changed blocks. + * + * @return the number of changes + */ + public int size() { + return getBlockChangeCount(); + } + + @Override + public Vector getMinimumPoint() { + return getWorld().getMinimumPoint(); + } + + @Override + public Vector getMaximumPoint() { + return getWorld().getMaximumPoint(); } /** * Finish off the queue. */ public void flushQueue() { - if (!queued) { - return; + Operations.completeBlindly(commit()); + } + + @Override + public @Nullable Operation commit() { + return bypassNone.commit(); + } + + public int countBlock(Region region, Set searchIDs) { + Set passOn = new HashSet(); + for (Integer i : searchIDs) { + passOn.add(new BaseBlock(i, -1)); } + return countBlocks(region, passOn); + } - final Set dirtyChunks = new HashSet(); - - for (Map.Entry entry : queueAfter) { - BlockVector pt = entry.getKey(); - rawSetBlock(pt, entry.getValue()); - - // TODO: use ChunkStore.toChunk(pt) after optimizing it. - if (fastMode) { - dirtyChunks.add(new BlockVector2D(pt.getBlockX() >> 4, pt.getBlockZ() >> 4)); - } - } - - // We don't want to place these blocks if other blocks were missing - // because it might cause the items to drop - if (blockBag == null || missingBlocks.size() == 0) { - for (Map.Entry entry : queueLast) { - BlockVector pt = entry.getKey(); - rawSetBlock(pt, entry.getValue()); - - // TODO: use ChunkStore.toChunk(pt) after optimizing it. - if (fastMode) { - dirtyChunks.add(new BlockVector2D(pt.getBlockX() >> 4, pt.getBlockZ() >> 4)); - } - } - - final Set blocks = new HashSet(); - final Map blockTypes = new HashMap(); - for (Map.Entry entry : queueFinal) { - final BlockVector pt = entry.getKey(); - blocks.add(pt); - blockTypes.put(pt, entry.getValue()); - } - - while (!blocks.isEmpty()) { - BlockVector current = blocks.iterator().next(); - if (!blocks.contains(current)) { - continue; - } - - final Deque walked = new LinkedList(); - - while (true) { - walked.addFirst(current); - - assert(blockTypes.containsKey(current)); - - final BaseBlock baseBlock = blockTypes.get(current); - - final int type = baseBlock.getType(); - final int data = baseBlock.getData(); - - switch (type) { - case BlockID.WOODEN_DOOR: - case BlockID.IRON_DOOR: - if ((data & 0x8) == 0) { - // Deal with lower door halves being attached to the floor AND the upper half - BlockVector upperBlock = current.add(0, 1, 0).toBlockVector(); - if (blocks.contains(upperBlock) && !walked.contains(upperBlock)) { - walked.addFirst(upperBlock); - } - } - break; - - case BlockID.MINECART_TRACKS: - case BlockID.POWERED_RAIL: - case BlockID.DETECTOR_RAIL: - case BlockID.ACTIVATOR_RAIL: - // Here, rails are hardcoded to be attached to the block below them. - // They're also attached to the block they're ascending towards via BlockType.getAttachment. - BlockVector lowerBlock = current.add(0, -1, 0).toBlockVector(); - if (blocks.contains(lowerBlock) && !walked.contains(lowerBlock)) { - walked.addFirst(lowerBlock); - } - break; - } - - final PlayerDirection attachment = BlockType.getAttachment(type, data); - if (attachment == null) { - // Block is not attached to anything => we can place it - break; - } - - current = current.add(attachment.vector()).toBlockVector(); - - if (!blocks.contains(current)) { - // We ran outside the remaing set => assume we can place blocks on this - break; - } - - if (walked.contains(current)) { - // Cycle detected => This will most likely go wrong, but there's nothing we can do about it. - break; - } - } - - for (BlockVector pt : walked) { - rawSetBlock(pt, blockTypes.get(pt)); - blocks.remove(pt); - - // TODO: use ChunkStore.toChunk(pt) after optimizing it. - if (fastMode) { - dirtyChunks.add(new BlockVector2D(pt.getBlockX() >> 4, pt.getBlockZ() >> 4)); - } - } - } - } - - if (!dirtyChunks.isEmpty()) world.fixAfterFastMode(dirtyChunks); - - queueAfter.clear(); - queueLast.clear(); - queueFinal.clear(); + /** + * Count the number of blocks of a list of types in a region. + * + * @param region the region + * @param searchBlocks the list of blocks to search + * @return the number of blocks that matched the pattern + */ + public int countBlocks(Region region, Set searchBlocks) { + FuzzyBlockMask mask = new FuzzyBlockMask(this, searchBlocks); + Counter count = new Counter(); + RegionMaskingFilter filter = new RegionMaskingFilter(mask, count); + RegionVisitor visitor = new RegionVisitor(region, filter); + Operations.completeBlindly(visitor); // We can't throw exceptions, nor do we expect any + return count.getCount(); } /** * Fills an area recursively in the X/Z directions. * - * @param origin - * @param block - * @param radius - * @param depth - * @param recursive + * @param origin the location to start from + * @param block the block to fill with + * @param radius the radius of the spherical area to fill + * @param depth the maximum depth, starting from the origin + * @param recursive whether a breadth-first search should be performed * @return number of blocks affected - * @throws MaxChangedBlocksException + * @throws MaxChangedBlocksException thrown if too many blocks are changed */ - public int fillXZ(Vector origin, BaseBlock block, double radius, int depth, - boolean recursive) throws MaxChangedBlocksException { - - int affected = 0; - int originX = origin.getBlockX(); - int originY = origin.getBlockY(); - int originZ = origin.getBlockZ(); - - HashSet visited = new HashSet(); - Stack queue = new Stack(); - - queue.push(new BlockVector(originX, originY, originZ)); - - while (!queue.empty()) { - BlockVector pt = queue.pop(); - int cx = pt.getBlockX(); - int cy = pt.getBlockY(); - int cz = pt.getBlockZ(); - - if (cy < 0 || cy > originY || visited.contains(pt)) { - continue; - } - - visited.add(pt); - - if (recursive) { - if (origin.distance(pt) > radius) { - continue; - } - - if (getBlock(pt).isAir()) { - if (setBlock(pt, block)) { - ++affected; - } - } else { - continue; - } - - queue.push(new BlockVector(cx, cy - 1, cz)); - queue.push(new BlockVector(cx, cy + 1, cz)); - } else { - double dist = Math.sqrt(Math.pow(originX - cx, 2) - + Math.pow(originZ - cz, 2)); - int minY = originY - depth + 1; - - if (dist > radius) { - continue; - } - - if (getBlock(pt).isAir()) { - affected += fillY(cx, originY, cz, block, minY); - } else { - continue; - } - } - - queue.push(new BlockVector(cx + 1, cy, cz)); - queue.push(new BlockVector(cx - 1, cy, cz)); - queue.push(new BlockVector(cx, cy, cz + 1)); - queue.push(new BlockVector(cx, cy, cz - 1)); - } - - return affected; - } - - /** - * Recursively fills a block and below until it hits another block. - * - * @param x - * @param cy - * @param z - * @param block - * @param minY - * @throws MaxChangedBlocksException - * @return - */ - private int fillY(int x, int cy, int z, BaseBlock block, int minY) + @SuppressWarnings("deprecation") + public int fillXZ(Vector origin, BaseBlock block, double radius, int depth, boolean recursive) throws MaxChangedBlocksException { - int affected = 0; - - for (int y = cy; y >= minY; --y) { - Vector pt = new Vector(x, y, z); - - if (getBlock(pt).isAir()) { - setBlock(pt, block); - ++affected; - } else { - break; - } - } - - return affected; + return fillXZ(origin, new SingleBlockPattern(block), radius, depth, recursive); } /** * Fills an area recursively in the X/Z directions. * - * @param origin - * @param pattern - * @param radius - * @param depth - * @param recursive + * @param origin the origin to start the fill from + * @param pattern the pattern to fill with + * @param radius the radius of the spherical area to fill, with 0 as the smallest radius + * @param depth the maximum depth, starting from the origin, with 1 as the smallest depth + * @param recursive whether a breadth-first search should be performed * @return number of blocks affected - * @throws MaxChangedBlocksException + * @throws MaxChangedBlocksException thrown if too many blocks are changed */ - public int fillXZ(Vector origin, Pattern pattern, double radius, int depth, - boolean recursive) throws MaxChangedBlocksException { + @SuppressWarnings("deprecation") + public int fillXZ(Vector origin, Pattern pattern, double radius, int depth, boolean recursive) throws MaxChangedBlocksException { + checkNotNull(origin); + checkNotNull(pattern); + checkArgument(radius >= 0, "radius >= 0"); + checkArgument(depth >= 1, "depth >= 1"); - int affected = 0; - int originX = origin.getBlockX(); - int originY = origin.getBlockY(); - int originZ = origin.getBlockZ(); + MaskIntersection mask = new MaskIntersection( + new RegionMask(new EllipsoidRegion(null, origin, new Vector(radius, radius, radius))), + new BoundedHeightMask( + Math.max(origin.getBlockY() - depth + 1, 0), + Math.min(getWorld().getMaxY(), origin.getBlockY())), + Masks.negate(new ExistingBlockMask(this))); - HashSet visited = new HashSet(); - Stack queue = new Stack(); + // Want to replace blocks + BlockReplace replace = new BlockReplace(this, Patterns.wrap(pattern)); - queue.push(new BlockVector(originX, originY, originZ)); - - while (!queue.empty()) { - BlockVector pt = queue.pop(); - int cx = pt.getBlockX(); - int cy = pt.getBlockY(); - int cz = pt.getBlockZ(); - - if (cy < 0 || cy > originY || visited.contains(pt)) { - continue; - } - - visited.add(pt); - - if (recursive) { - if (origin.distance(pt) > radius) { - continue; - } - - if (getBlock(pt).isAir()) { - if (setBlock(pt, pattern.next(pt))) { - ++affected; - } - } else { - continue; - } - - queue.push(new BlockVector(cx, cy - 1, cz)); - queue.push(new BlockVector(cx, cy + 1, cz)); - } else { - double dist = Math.sqrt(Math.pow(originX - cx, 2) - + Math.pow(originZ - cz, 2)); - int minY = originY - depth + 1; - - if (dist > radius) { - continue; - } - - if (getBlock(pt).isAir()) { - affected += fillY(cx, originY, cz, pattern, minY); - } else { - continue; - } - } - - queue.push(new BlockVector(cx + 1, cy, cz)); - queue.push(new BlockVector(cx - 1, cy, cz)); - queue.push(new BlockVector(cx, cy, cz + 1)); - queue.push(new BlockVector(cx, cy, cz - 1)); - } - - return affected; - } - - /** - * Recursively fills a block and below until it hits another block. - * - * @param x - * @param cy - * @param z - * @param pattern - * @param minY - * @throws MaxChangedBlocksException - * @return - */ - private int fillY(int x, int cy, int z, Pattern pattern, int minY) - throws MaxChangedBlocksException { - int affected = 0; - - for (int y = cy; y >= minY; --y) { - Vector pt = new Vector(x, y, z); - - if (getBlock(pt).isAir()) { - setBlock(pt, pattern.next(pt)); - ++affected; - } else { - break; - } - } - - return affected; - } - - /** - * Remove blocks above. - * - * @param pos - * @param size - * @param height - * @return number of blocks affected - * @throws MaxChangedBlocksException - */ - public int removeAbove(Vector pos, int size, int height) - throws MaxChangedBlocksException { - int maxY = Math.min(world.getMaxY(), pos.getBlockY() + height - 1); - --size; - int affected = 0; - - int oX = pos.getBlockX(); - int oY = pos.getBlockY(); - int oZ = pos.getBlockZ(); - - for (int x = oX - size; x <= oX + size; ++x) { - for (int z = oZ - size; z <= oZ + size; ++z) { - for (int y = oY; y <= maxY; ++y) { - Vector pt = new Vector(x, y, z); - - if (getBlockType(pt) != BlockID.AIR) { - setBlock(pt, new BaseBlock(BlockID.AIR)); - ++affected; - } - } - } - } - - return affected; - } - - /** - * Remove blocks below. - * - * @param pos - * @param size - * @param height - * @return number of blocks affected - * @throws MaxChangedBlocksException - */ - public int removeBelow(Vector pos, int size, int height) - throws MaxChangedBlocksException { - int minY = Math.max(0, pos.getBlockY() - height); - --size; - int affected = 0; - - int oX = pos.getBlockX(); - int oY = pos.getBlockY(); - int oZ = pos.getBlockZ(); - - for (int x = oX - size; x <= oX + size; ++x) { - for (int z = oZ - size; z <= oZ + size; ++z) { - for (int y = oY; y >= minY; --y) { - Vector pt = new Vector(x, y, z); - - if (getBlockType(pt) != BlockID.AIR) { - setBlock(pt, new BaseBlock(BlockID.AIR)); - ++affected; - } - } - } - } - - return affected; - } - - /** - * Remove nearby blocks of a type. - * - * @param pos - * @param blockType - * @param size - * @return number of blocks affected - * @throws MaxChangedBlocksException - */ - public int removeNear(Vector pos, int blockType, int size) - throws MaxChangedBlocksException { - int affected = 0; - BaseBlock air = new BaseBlock(BlockID.AIR); - - int minX = pos.getBlockX() - size; - int maxX = pos.getBlockX() + size; - int minY = Math.max(0, pos.getBlockY() - size); - int maxY = Math.min(world.getMaxY(), pos.getBlockY() + size); - int minZ = pos.getBlockZ() - size; - int maxZ = pos.getBlockZ() + size; - - for (int x = minX; x <= maxX; ++x) { - for (int y = minY; y <= maxY; ++y) { - for (int z = minZ; z <= maxZ; ++z) { - Vector p = new Vector(x, y, z); - - if (getBlockType(p) == blockType) { - if (setBlock(p, air)) { - ++affected; - } - } - } - } - } - - return affected; - } - - /** - * Sets all the blocks inside a region to a certain block type. - * - * @param region - * @param block - * @return number of blocks affected - * @throws MaxChangedBlocksException - */ - public int setBlocks(Region region, BaseBlock block) - throws MaxChangedBlocksException { - int affected = 0; - - if (region instanceof CuboidRegion) { - // Doing this for speed - Vector min = region.getMinimumPoint(); - Vector max = region.getMaximumPoint(); - - int minX = min.getBlockX(); - int minY = min.getBlockY(); - int minZ = min.getBlockZ(); - int maxX = max.getBlockX(); - int maxY = max.getBlockY(); - int maxZ = max.getBlockZ(); - - for (int x = minX; x <= maxX; ++x) { - for (int y = minY; y <= maxY; ++y) { - for (int z = minZ; z <= maxZ; ++z) { - Vector pt = new Vector(x, y, z); - - if (setBlock(pt, block)) { - ++affected; - } - } - } - } + // Pick how we're going to visit blocks + RecursiveVisitor visitor; + if (recursive) { + visitor = new RecursiveVisitor(mask, replace); } else { - for (Vector pt : region) { - if (setBlock(pt, block)) { - ++affected; - } - } + visitor = new DownwardVisitor(mask, replace, origin.getBlockY()); } - return affected; + // Start at the origin + visitor.visit(origin); + + // Execute + Operations.completeLegacy(visitor); + + return visitor.getAffected(); } /** - * Sets all the blocks inside a region to a certain block type. + * Remove a cuboid above the given position with a given apothem and a given height. * - * @param region - * @param pattern + * @param position base position + * @param apothem an apothem of the cuboid (on the XZ plane), where the minimum is 1 + * @param height the height of the cuboid, where the minimum is 1 * @return number of blocks affected - * @throws MaxChangedBlocksException + * @throws MaxChangedBlocksException thrown if too many blocks are changed */ - public int setBlocks(Region region, Pattern pattern) - throws MaxChangedBlocksException { - int affected = 0; + @SuppressWarnings("deprecation") + public int removeAbove(Vector position, int apothem, int height) throws MaxChangedBlocksException { + checkNotNull(position); + checkArgument(apothem >= 1, "apothem >= 1"); + checkArgument(height >= 1, "height >= 1"); - if (region instanceof CuboidRegion) { - // Doing this for speed - Vector min = region.getMinimumPoint(); - Vector max = region.getMaximumPoint(); - - int minX = min.getBlockX(); - int minY = min.getBlockY(); - int minZ = min.getBlockZ(); - int maxX = max.getBlockX(); - int maxY = max.getBlockY(); - int maxZ = max.getBlockZ(); - - for (int x = minX; x <= maxX; ++x) { - for (int y = minY; y <= maxY; ++y) { - for (int z = minZ; z <= maxZ; ++z) { - Vector pt = new Vector(x, y, z); - - if (setBlock(pt, pattern.next(pt))) { - ++affected; - } - } - } - } - } else { - for (Vector pt : region) { - if (setBlock(pt, pattern.next(pt))) { - ++affected; - } - } - } - - return affected; + Region region = new CuboidRegion( + getWorld(), // Causes clamping of Y range + position.add(-apothem + 1, 0, -apothem + 1), + position.add(apothem - 1, height - 1, apothem - 1)); + Pattern pattern = new SingleBlockPattern(new BaseBlock(BlockID.AIR)); + return setBlocks(region, pattern); } /** - * Replaces all the blocks of a type inside a region to another block type. + * Remove a cuboid below the given position with a given apothem and a given height. * - * @param region - * @param fromBlockTypes -1 for non-air - * @param toBlock + * @param position base position + * @param apothem an apothem of the cuboid (on the XZ plane), where the minimum is 1 + * @param height the height of the cuboid, where the minimum is 1 * @return number of blocks affected - * @throws MaxChangedBlocksException + * @throws MaxChangedBlocksException thrown if too many blocks are changed */ - public int replaceBlocks(Region region, Set fromBlockTypes, BaseBlock toBlock) throws MaxChangedBlocksException { - Set definiteBlockTypes = new HashSet(); - Set fuzzyBlockTypes = new HashSet(); + @SuppressWarnings("deprecation") + public int removeBelow(Vector position, int apothem, int height) throws MaxChangedBlocksException { + checkNotNull(position); + checkArgument(apothem >= 1, "apothem >= 1"); + checkArgument(height >= 1, "height >= 1"); - if (fromBlockTypes != null) { - for (BaseBlock block : fromBlockTypes) { - if (block.getData() == -1) { - fuzzyBlockTypes.add(block.getType()); - } else { - definiteBlockTypes.add(block); - } - } - } - - int affected = 0; - - if (region instanceof CuboidRegion) { - // Doing this for speed - Vector min = region.getMinimumPoint(); - Vector max = region.getMaximumPoint(); - - int minX = min.getBlockX(); - int minY = min.getBlockY(); - int minZ = min.getBlockZ(); - int maxX = max.getBlockX(); - int maxY = max.getBlockY(); - int maxZ = max.getBlockZ(); - - for (int x = minX; x <= maxX; ++x) { - for (int y = minY; y <= maxY; ++y) { - for (int z = minZ; z <= maxZ; ++z) { - Vector pt = new Vector(x, y, z); - BaseBlock curBlockType = getBlock(pt); - - if (fromBlockTypes == null) { - //replace - if (curBlockType.isAir()) { - continue; - } - } else { - //replace - if (!definiteBlockTypes.contains(curBlockType) && !fuzzyBlockTypes.contains(curBlockType.getType())) { - continue; - } - } - - if (setBlock(pt, toBlock)) { - ++affected; - } - } - } - } - } else { - for (Vector pt : region) { - BaseBlock curBlockType = getBlock(pt); - - if (fromBlockTypes == null) { - //replace - if (curBlockType.isAir()) { - continue; - } - } else { - //replace - if (!definiteBlockTypes.contains(curBlockType) && !fuzzyBlockTypes.contains(curBlockType.getType())) { - continue; - } - } - - if (setBlock(pt, toBlock)) { - ++affected; - } - } - } - - return affected; + Region region = new CuboidRegion( + getWorld(), // Causes clamping of Y range + position.add(-apothem + 1, 0, -apothem + 1), + position.add(apothem - 1, -height + 1, apothem - 1)); + Pattern pattern = new SingleBlockPattern(new BaseBlock(BlockID.AIR)); + return setBlocks(region, pattern); } /** - * Replaces all the blocks of a type inside a region to another block type. + * Remove blocks of a certain type nearby a given position. * - * @param region - * @param fromBlockTypes -1 for non-air - * @param pattern + * @param position center position of cuboid + * @param blockType the block type to match + * @param apothem an apothem of the cuboid, where the minimum is 1 * @return number of blocks affected - * @throws MaxChangedBlocksException + * @throws MaxChangedBlocksException thrown if too many blocks are changed */ - public int replaceBlocks(Region region, Set fromBlockTypes, Pattern pattern) throws MaxChangedBlocksException { - Set definiteBlockTypes = new HashSet(); - Set fuzzyBlockTypes = new HashSet(); - if (fromBlockTypes != null) { - for (BaseBlock block : fromBlockTypes) { - if (block.getData() == -1) { - fuzzyBlockTypes.add(block.getType()); - } else { - definiteBlockTypes.add(block); - } - } - } + @SuppressWarnings("deprecation") + public int removeNear(Vector position, int blockType, int apothem) throws MaxChangedBlocksException { + checkNotNull(position); + checkArgument(apothem >= 1, "apothem >= 1"); - int affected = 0; - - if (region instanceof CuboidRegion) { - // Doing this for speed - Vector min = region.getMinimumPoint(); - Vector max = region.getMaximumPoint(); - - int minX = min.getBlockX(); - int minY = min.getBlockY(); - int minZ = min.getBlockZ(); - int maxX = max.getBlockX(); - int maxY = max.getBlockY(); - int maxZ = max.getBlockZ(); - - for (int x = minX; x <= maxX; ++x) { - for (int y = minY; y <= maxY; ++y) { - for (int z = minZ; z <= maxZ; ++z) { - Vector pt = new Vector(x, y, z); - BaseBlock curBlockType = getBlock(pt); - - if (fromBlockTypes == null) { - //replace - if (curBlockType.isAir()) { - continue; - } - } else { - //replace - if (!definiteBlockTypes.contains(curBlockType) && !fuzzyBlockTypes.contains(curBlockType.getType())) { - continue; - } - } - - if (setBlock(pt, pattern.next(pt))) { - ++affected; - } - } - } - } - } else { - for (Vector pt : region) { - BaseBlock curBlockType = getBlock(pt); - - if (fromBlockTypes == null) { - //replace - if (curBlockType.isAir()) { - continue; - } - } else { - //replace - if (!definiteBlockTypes.contains(curBlockType) && !fuzzyBlockTypes.contains(curBlockType.getType())) { - continue; - } - } - - if (setBlock(pt, pattern.next(pt))) { - ++affected; - } - } - } - - return affected; + Mask mask = new com.sk89q.worldedit.masks.FuzzyBlockMask(new BaseBlock(blockType, -1)); + Vector adjustment = new Vector(1, 1, 1).multiply(apothem - 1); + Region region = new CuboidRegion( + getWorld(), // Causes clamping of Y range + position.add(adjustment.multiply(-1)), + position.add(adjustment)); + Pattern pattern = new SingleBlockPattern(new BaseBlock(BlockID.AIR)); + return replaceBlocks(region, mask, pattern); } - public int center(Region region, Pattern pattern) - throws MaxChangedBlocksException { + /** + * Sets all the blocks inside a region to a given block type. + * + * @param region the region + * @param block the block + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + @SuppressWarnings("deprecation") + public int setBlocks(Region region, BaseBlock block) throws MaxChangedBlocksException { + return setBlocks(region, new SingleBlockPattern(block)); + } + + /** + * Sets all the blocks inside a region to a given pattern. + * + * @param region the region + * @param pattern the pattern that provides the replacement block + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + @SuppressWarnings("deprecation") + public int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException { + checkNotNull(region); + checkNotNull(pattern); + + BlockReplace replace = new BlockReplace(this, Patterns.wrap(pattern)); + RegionVisitor visitor = new RegionVisitor(region, replace); + Operations.completeLegacy(visitor); + return visitor.getAffected(); + } + + /** + * Replaces all the blocks matching a given filter, within a given region, to a block + * returned by a given pattern. + * + * @param region the region to replace the blocks within + * @param filter a list of block types to match, or null to use {@link com.sk89q.worldedit.masks.ExistingBlockMask} + * @param replacement the replacement block + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + @SuppressWarnings("deprecation") + public int replaceBlocks(Region region, Set filter, BaseBlock replacement) throws MaxChangedBlocksException { + return replaceBlocks(region, filter, new SingleBlockPattern(replacement)); + } + + /** + * Replaces all the blocks matching a given filter, within a given region, to a block + * returned by a given pattern. + * + * @param region the region to replace the blocks within + * @param filter a list of block types to match, or null to use {@link com.sk89q.worldedit.masks.ExistingBlockMask} + * @param pattern the pattern that provides the new blocks + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + @SuppressWarnings("deprecation") + public int replaceBlocks(Region region, Set filter, Pattern pattern) throws MaxChangedBlocksException { + Mask mask = filter == null ? new com.sk89q.worldedit.masks.ExistingBlockMask() : new com.sk89q.worldedit.masks.FuzzyBlockMask(filter); + return replaceBlocks(region, mask, pattern); + } + + /** + * Replaces all the blocks matching a given mask, within a given region, to a block + * returned by a given pattern. + * + * @param region the region to replace the blocks within + * @param mask the mask that blocks must match + * @param pattern the pattern that provides the new blocks + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + @SuppressWarnings("deprecation") + public int replaceBlocks(Region region, Mask mask, Pattern pattern) throws MaxChangedBlocksException { + checkNotNull(region); + checkNotNull(mask); + checkNotNull(pattern); + + BlockReplace replace = new BlockReplace(this, Patterns.wrap(pattern)); + RegionMaskingFilter filter = new RegionMaskingFilter(Masks.wrap(mask, this), replace); + RegionVisitor visitor = new RegionVisitor(region, filter); + Operations.completeLegacy(visitor); + return visitor.getAffected(); + } + + /** + * Sets the blocks at the center of the given region to the given pattern. + * If the center sits between two blocks on a certain axis, then two blocks + * will be placed to mark the center. + * + * @param region the region to find the center of + * @param pattern the replacement pattern + * @return the number of blocks placed + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + @SuppressWarnings("deprecation") + public int center(Region region, Pattern pattern) throws MaxChangedBlocksException { + checkNotNull(region); + checkNotNull(pattern); + Vector center = region.getCenter(); - int x2 = center.getBlockX(); - int y2 = center.getBlockY(); - int z2 = center.getBlockZ(); - - int affected = 0; - for (int x = (int) center.getX(); x <= x2; x++) { - for (int y = (int) center.getY(); y <= y2; y++) { - for (int z = (int) center.getZ(); z <= z2; z++) { - if (setBlock(new Vector(x, y, z), pattern)) { - affected++; - } - } - } - } - - return affected; + Region centerRegion = new CuboidRegion( + getWorld(), // Causes clamping of Y range + new Vector((int) center.getX(), (int) center.getY(), (int) center.getZ()), + center.toBlockVector()); + return setBlocks(centerRegion, pattern); } /** - * Make faces of the region (as if it was a cuboid if it's not). + * Make the faces of the given region as if it was a {@link CuboidRegion}. * - * @param region - * @param block + * @param region the region + * @param block the block to place * @return number of blocks affected * @throws MaxChangedBlocksException */ - public int makeCuboidFaces(Region region, BaseBlock block) - throws MaxChangedBlocksException { - int affected = 0; - - Vector min = region.getMinimumPoint(); - Vector max = region.getMaximumPoint(); - - int minX = min.getBlockX(); - int minY = min.getBlockY(); - int minZ = min.getBlockZ(); - int maxX = max.getBlockX(); - int maxY = max.getBlockY(); - int maxZ = max.getBlockZ(); - - for (int x = minX; x <= maxX; ++x) { - for (int y = minY; y <= maxY; ++y) { - if (setBlock(new Vector(x, y, minZ), block)) { - ++affected; - } - if (setBlock(new Vector(x, y, maxZ), block)) { - ++affected; - } - ++affected; - } - } - - for (int y = minY; y <= maxY; ++y) { - for (int z = minZ; z <= maxZ; ++z) { - if (setBlock(new Vector(minX, y, z), block)) { - ++affected; - } - if (setBlock(new Vector(maxX, y, z), block)) { - ++affected; - } - } - } - - for (int z = minZ; z <= maxZ; ++z) { - for (int x = minX; x <= maxX; ++x) { - if (setBlock(new Vector(x, minY, z), block)) { - ++affected; - } - if (setBlock(new Vector(x, maxY, z), block)) { - ++affected; - } - } - } - - return affected; + @SuppressWarnings("deprecation") + public int makeCuboidFaces(Region region, BaseBlock block) throws MaxChangedBlocksException { + return makeCuboidFaces(region, new SingleBlockPattern(block)); } /** - * Make faces of the region (as if it was a cuboid if it's not). + * Make the faces of the given region as if it was a {@link CuboidRegion}. * - * @param region - * @param pattern + * @param region the region + * @param pattern the pattern to place * @return number of blocks affected - * @throws MaxChangedBlocksException + * @throws MaxChangedBlocksException thrown if too many blocks are changed */ - public int makeCuboidFaces(Region region, Pattern pattern) - throws MaxChangedBlocksException { - int affected = 0; + @SuppressWarnings("deprecation") + public int makeCuboidFaces(Region region, Pattern pattern) throws MaxChangedBlocksException { + checkNotNull(region); + checkNotNull(pattern); - Vector min = region.getMinimumPoint(); - Vector max = region.getMaximumPoint(); - - int minX = min.getBlockX(); - int minY = min.getBlockY(); - int minZ = min.getBlockZ(); - int maxX = max.getBlockX(); - int maxY = max.getBlockY(); - int maxZ = max.getBlockZ(); - - for (int x = minX; x <= maxX; ++x) { - for (int y = minY; y <= maxY; ++y) { - Vector minV = new Vector(x, y, minZ); - if (setBlock(minV, pattern.next(minV))) { - ++affected; - } - Vector maxV = new Vector(x, y, maxZ); - if (setBlock(maxV, pattern.next(maxV))) { - ++affected; - } - ++affected; - } - } - - for (int y = minY; y <= maxY; ++y) { - for (int z = minZ; z <= maxZ; ++z) { - Vector minV = new Vector(minX, y, z); - if (setBlock(minV, pattern.next(minV))) { - ++affected; - } - Vector maxV = new Vector(maxX, y, z); - if (setBlock(maxV, pattern.next(maxV))) { - ++affected; - } - } - } - - for (int z = minZ; z <= maxZ; ++z) { - for (int x = minX; x <= maxX; ++x) { - Vector minV = new Vector(x, minY, z); - if (setBlock(minV, pattern.next(minV))) { - ++affected; - } - Vector maxV = new Vector(x, maxY, z); - if (setBlock(maxV, pattern.next(maxV))) { - ++affected; - } - } - } - - return affected; + CuboidRegion cuboid = CuboidRegion.makeCuboid(region); + Region faces = cuboid.getFaces(); + return setBlocks(faces, pattern); } /** - * Make faces of the region + * Make the faces of the given region. The method by which the faces are found + * may be inefficient, because there may not be an efficient implementation supported + * for that specific shape. * - * @param region - * @param pattern + * @param region the region + * @param pattern the pattern to place * @return number of blocks affected - * @throws MaxChangedBlocksException + * @throws MaxChangedBlocksException thrown if too many blocks are changed */ + @SuppressWarnings("deprecation") public int makeFaces(final Region region, Pattern pattern) throws MaxChangedBlocksException { - return new RegionShape(region).generate(this, pattern, true); + checkNotNull(region); + checkNotNull(pattern); + + if (region instanceof CuboidRegion) { + return makeCuboidFaces(region, pattern); + } else { + return new RegionShape(region).generate(this, pattern, true); + } } /** - * Make walls of the region (as if it was a cuboid if it's not). + * Make the walls (all faces but those parallel to the X-Z plane) of the given region + * as if it was a {@link CuboidRegion}. * - * @param region - * @param block + * @param region the region + * @param block the block to place * @return number of blocks affected * @throws MaxChangedBlocksException */ - public int makeCuboidWalls(Region region, BaseBlock block) - throws MaxChangedBlocksException { - int affected = 0; - - Vector min = region.getMinimumPoint(); - Vector max = region.getMaximumPoint(); - - int minX = min.getBlockX(); - int minY = min.getBlockY(); - int minZ = min.getBlockZ(); - int maxX = max.getBlockX(); - int maxY = max.getBlockY(); - int maxZ = max.getBlockZ(); - - for (int x = minX; x <= maxX; ++x) { - for (int y = minY; y <= maxY; ++y) { - if (setBlock(new Vector(x, y, minZ), block)) { - ++affected; - } - if (setBlock(new Vector(x, y, maxZ), block)) { - ++affected; - } - ++affected; - } - } - - for (int y = minY; y <= maxY; ++y) { - for (int z = minZ; z <= maxZ; ++z) { - if (setBlock(new Vector(minX, y, z), block)) { - ++affected; - } - if (setBlock(new Vector(maxX, y, z), block)) { - ++affected; - } - } - } - - return affected; + @SuppressWarnings("deprecation") + public int makeCuboidWalls(Region region, BaseBlock block) throws MaxChangedBlocksException { + return makeCuboidWalls(region, new SingleBlockPattern(block)); } /** - * Make walls of the region (as if it was a cuboid if it's not). + * Make the walls (all faces but those parallel to the X-Z plane) of the given region + * as if it was a {@link CuboidRegion}. * - * @param region - * @param pattern + * @param region the region + * @param pattern the pattern to place * @return number of blocks affected - * @throws MaxChangedBlocksException + * @throws MaxChangedBlocksException thrown if too many blocks are changed */ - public int makeCuboidWalls(Region region, Pattern pattern) - throws MaxChangedBlocksException { - int affected = 0; + @SuppressWarnings("deprecation") + public int makeCuboidWalls(Region region, Pattern pattern) throws MaxChangedBlocksException { + checkNotNull(region); + checkNotNull(pattern); - Vector min = region.getMinimumPoint(); - Vector max = region.getMaximumPoint(); - - int minX = min.getBlockX(); - int minY = min.getBlockY(); - int minZ = min.getBlockZ(); - int maxX = max.getBlockX(); - int maxY = max.getBlockY(); - int maxZ = max.getBlockZ(); - - for (int x = minX; x <= maxX; ++x) { - for (int y = minY; y <= maxY; ++y) { - Vector minV = new Vector(x, y, minZ); - if (setBlock(minV, pattern.next(minV))) { - ++affected; - } - Vector maxV = new Vector(x, y, maxZ); - if (setBlock(maxV, pattern.next(maxV))) { - ++affected; - } - ++affected; - } - } - - for (int y = minY; y <= maxY; ++y) { - for (int z = minZ; z <= maxZ; ++z) { - Vector minV = new Vector(minX, y, z); - if (setBlock(minV, pattern.next(minV))) { - ++affected; - } - Vector maxV = new Vector(maxX, y, z); - if (setBlock(maxV, pattern.next(maxV))) { - ++affected; - } - } - } - - return affected; + CuboidRegion cuboid = CuboidRegion.makeCuboid(region); + Region faces = cuboid.getWalls(); + return setBlocks(faces, pattern); } /** - * Make walls of the region + * Make the walls of the given region. The method by which the walls are found + * may be inefficient, because there may not be an efficient implementation supported + * for that specific shape. * - * @param region - * @param pattern + * @param region the region + * @param pattern the pattern to place * @return number of blocks affected - * @throws MaxChangedBlocksException + * @throws MaxChangedBlocksException thrown if too many blocks are changed */ + @SuppressWarnings("deprecation") public int makeWalls(final Region region, Pattern pattern) throws MaxChangedBlocksException { - final int minY = region.getMinimumPoint().getBlockY(); - final int maxY = region.getMaximumPoint().getBlockY(); - final ArbitraryShape shape = new RegionShape(region) { - @Override - protected BaseBlock getMaterial(int x, int y, int z, BaseBlock defaultMaterial) { - if (y > maxY || y < minY) { - // Put holes into the floor and ceiling by telling ArbitraryShape that the shape goes on outside the region - return defaultMaterial; - } + checkNotNull(region); + checkNotNull(pattern); - return super.getMaterial(x, y, z, defaultMaterial); - } - }; - return shape.generate(this, pattern, true); + if (region instanceof CuboidRegion) { + return makeCuboidWalls(region, pattern); + } else { + final int minY = region.getMinimumPoint().getBlockY(); + final int maxY = region.getMaximumPoint().getBlockY(); + final ArbitraryShape shape = new RegionShape(region) { + @Override + protected BaseBlock getMaterial(int x, int y, int z, BaseBlock defaultMaterial) { + if (y > maxY || y < minY) { + // Put holes into the floor and ceiling by telling ArbitraryShape that the shape goes on outside the region + return defaultMaterial; + } + + return super.getMaterial(x, y, z, defaultMaterial); + } + }; + return shape.generate(this, pattern, true); + } } /** - * Overlays a layer of blocks over a cuboid area. + * Places a layer of blocks on top of ground blocks in the given region + * (as if it were a cuboid). * - * @param region - * @param block + * @param region the region + * @param block the placed block * @return number of blocks affected - * @throws MaxChangedBlocksException + * @throws MaxChangedBlocksException thrown if too many blocks are changed */ - public int overlayCuboidBlocks(Region region, BaseBlock block) - throws MaxChangedBlocksException { - Vector min = region.getMinimumPoint(); - Vector max = region.getMaximumPoint(); + @SuppressWarnings("deprecation") + public int overlayCuboidBlocks(Region region, BaseBlock block) throws MaxChangedBlocksException { + checkNotNull(block); - int upperY = Math.min(world.getMaxY(), max.getBlockY() + 1); - int lowerY = Math.max(0, min.getBlockY() - 1); - - int affected = 0; - - int minX = min.getBlockX(); - int minZ = min.getBlockZ(); - int maxX = max.getBlockX(); - int maxZ = max.getBlockZ(); - - for (int x = minX; x <= maxX; ++x) { - for (int z = minZ; z <= maxZ; ++z) { - for (int y = upperY; y >= lowerY; --y) { - Vector above = new Vector(x, y + 1, z); - - if (y + 1 <= world.getMaxY() && !getBlock(new Vector(x, y, z)).isAir() - && getBlock(above).isAir()) { - if (setBlock(above, block)) { - ++affected; - } - break; - } - } - } - } - - return affected; + return overlayCuboidBlocks(region, new SingleBlockPattern(block)); } /** - * Overlays a layer of blocks over a cuboid area. + * Places a layer of blocks on top of ground blocks in the given region + * (as if it were a cuboid). * - * @param region - * @param pattern + * @param region the region + * @param pattern the placed block pattern * @return number of blocks affected - * @throws MaxChangedBlocksException + * @throws MaxChangedBlocksException thrown if too many blocks are changed */ - public int overlayCuboidBlocks(Region region, Pattern pattern) - throws MaxChangedBlocksException { - Vector min = region.getMinimumPoint(); - Vector max = region.getMaximumPoint(); + @SuppressWarnings("deprecation") + public int overlayCuboidBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException { + checkNotNull(region); + checkNotNull(pattern); - int upperY = Math.min(world.getMaxY(), max.getBlockY() + 1); - int lowerY = Math.max(0, min.getBlockY() - 1); - - int affected = 0; - - int minX = min.getBlockX(); - int minZ = min.getBlockZ(); - int maxX = max.getBlockX(); - int maxZ = max.getBlockZ(); - - for (int x = minX; x <= maxX; ++x) { - for (int z = minZ; z <= maxZ; ++z) { - for (int y = upperY; y >= lowerY; --y) { - Vector above = new Vector(x, y + 1, z); - - if (y + 1 <= world.getMaxY() && !getBlock(new Vector(x, y, z)).isAir() - && getBlock(above).isAir()) { - if (setBlock(above, pattern.next(above))) { - ++affected; - } - break; - } - } - } - } - - return affected; + BlockReplace replace = new BlockReplace(this, Patterns.wrap(pattern)); + RegionOffset offset = new RegionOffset(new Vector(0, 1, 0), replace); + GroundFunction ground = new GroundFunction(new ExistingBlockMask(this), offset); + LayerVisitor visitor = new LayerVisitor(asFlatRegion(region), minimumBlockY(region), maximumBlockY(region), ground); + Operations.completeLegacy(visitor); + return ground.getAffected(); } /** * Turns the first 3 layers into dirt/grass and the bottom layers * into rock, like a natural Minecraft mountain. * - * @param region + * @param region the region to affect * @return number of blocks affected - * @throws MaxChangedBlocksException + * @throws MaxChangedBlocksException thrown if too many blocks are changed */ - public int naturalizeCuboidBlocks(Region region) - throws MaxChangedBlocksException { - Vector min = region.getMinimumPoint(); - Vector max = region.getMaximumPoint(); + public int naturalizeCuboidBlocks(Region region) throws MaxChangedBlocksException { + checkNotNull(region); - int upperY = Math.min(world.getMaxY(), max.getBlockY() + 1); - int lowerY = Math.max(0, min.getBlockY() - 1); - - int affected = 0; - - int minX = min.getBlockX(); - int minZ = min.getBlockZ(); - int maxX = max.getBlockX(); - int maxZ = max.getBlockZ(); - - BaseBlock grass = new BaseBlock(BlockID.GRASS); - BaseBlock dirt = new BaseBlock(BlockID.DIRT); - BaseBlock stone = new BaseBlock(BlockID.STONE); - - for (int x = minX; x <= maxX; ++x) { - for (int z = minZ; z <= maxZ; ++z) { - int level = -1; - - for (int y = upperY; y >= lowerY; --y) { - Vector pt = new Vector(x, y, z); - //Vector above = new Vector(x, y + 1, z); - int blockType = getBlockType(pt); - - boolean isTransformable = - blockType == BlockID.GRASS - || blockType == BlockID.DIRT - || blockType == BlockID.STONE; - - // Still searching for the top block - if (level == -1) { - if (!isTransformable) { - continue; // Not transforming this column yet - } - - level = 0; - } - - if (level >= 0) { - if (isTransformable) { - if (level == 0) { - setBlock(pt, grass); - affected++; - } else if (level <= 2) { - setBlock(pt, dirt); - affected++; - } else { - setBlock(pt, stone); - affected++; - } - } - - level++; - } - } - } - } - - return affected; + Naturalizer naturalizer = new Naturalizer(this); + FlatRegion flatRegion = Regions.asFlatRegion(region); + LayerVisitor visitor = new LayerVisitor(flatRegion, minimumBlockY(region), maximumBlockY(region), naturalizer); + Operations.completeLegacy(visitor); + return naturalizer.getAffected(); } /** * Stack a cuboid region. * - * @param region - * @param dir - * @param count - * @param copyAir + * @param region the region to stack + * @param dir the direction to stack + * @param count the number of times to stack + * @param copyAir true to also copy air blocks * @return number of blocks affected - * @throws MaxChangedBlocksException + * @throws MaxChangedBlocksException thrown if too many blocks are changed */ - public int stackCuboidRegion(Region region, Vector dir, int count, - boolean copyAir) throws MaxChangedBlocksException { - int affected = 0; + public int stackCuboidRegion(Region region, Vector dir, int count, boolean copyAir) throws MaxChangedBlocksException { + checkNotNull(region); + checkNotNull(dir); + checkArgument(count >= 1, "count >= 1 required"); - Vector min = region.getMinimumPoint(); - Vector max = region.getMaximumPoint(); - - int minX = min.getBlockX(); - int minY = min.getBlockY(); - int minZ = min.getBlockZ(); - int maxX = max.getBlockX(); - int maxY = max.getBlockY(); - int maxZ = max.getBlockZ(); - - int xs = region.getWidth(); - int ys = region.getHeight(); - int zs = region.getLength(); - - for (int x = minX; x <= maxX; ++x) { - for (int z = minZ; z <= maxZ; ++z) { - for (int y = minY; y <= maxY; ++y) { - BaseBlock block = getBlock(new Vector(x, y, z)); - - if (!block.isAir() || copyAir) { - for (int i = 1; i <= count; ++i) { - Vector pos = new Vector(x + xs * dir.getBlockX() - * i, y + ys * dir.getBlockY() * i, z + zs - * dir.getBlockZ() * i); - - if (setBlock(pos, block)) { - ++affected; - } - } - } - } - } + Vector size = region.getMaximumPoint().subtract(region.getMinimumPoint()).add(1, 1, 1); + Vector to = region.getMinimumPoint(); + ForwardExtentCopy copy = new ForwardExtentCopy(this, region, this, to); + copy.setRepetitions(count); + copy.setTransform(new AffineTransform().translate(dir.multiply(size))); + if (!copyAir) { + copy.setSourceMask(new ExistingBlockMask(this)); } - - return affected; + Operations.completeLegacy(copy); + return copy.getAffected(); } /** - * Move a region. + * Move the blocks in a region a certain direction. * - * @param region - * @param dir - * @param distance - * @param copyAir - * @param replace + * @param region the region to move + * @param dir the direction + * @param distance the distance to move + * @param copyAir true to copy air blocks + * @param replacement the replacement block to fill in after moving, or null to use air * @return number of blocks moved - * @throws MaxChangedBlocksException - * @throws RegionOperationException + * @throws MaxChangedBlocksException thrown if too many blocks are changed */ - public int moveRegion(Region region, Vector dir, int distance, - boolean copyAir, BaseBlock replace) - throws MaxChangedBlocksException, RegionOperationException { - int affected = 0; + public int moveRegion(Region region, Vector dir, int distance, boolean copyAir, BaseBlock replacement) throws MaxChangedBlocksException { + checkNotNull(region); + checkNotNull(dir); + checkArgument(distance >= 1, "distance >= 1 required"); - final Vector shift = dir.multiply(distance); + Vector to = region.getMinimumPoint(); - final Region newRegion = region.clone(); - newRegion.shift(shift); + // Remove the original blocks + com.sk89q.worldedit.function.pattern.Pattern pattern = replacement != null ? + new BlockPattern(replacement) : + new BlockPattern(new BaseBlock(BlockID.AIR)); + BlockReplace remove = new BlockReplace(this, pattern); - final Map delayed = new LinkedHashMap(); - - for (Vector pos : region) { - final BaseBlock block = getBlock(pos); - - if (!block.isAir() || copyAir) { - final Vector newPos = pos.add(shift); - - delayed.put(newPos, getBlock(pos)); - - // Don't want to replace the old block if it's in - // the new area - if (!newRegion.contains(pos)) { - setBlock(pos, replace); - } - } + // Copy to a buffer so we don't destroy our original before we can copy all the blocks from it + ForgetfulExtentBuffer buffer = new ForgetfulExtentBuffer(this, new RegionMask(region)); + ForwardExtentCopy copy = new ForwardExtentCopy(this, region, buffer, to); + copy.setTransform(new AffineTransform().translate(dir.multiply(distance))); + copy.setSourceFunction(remove); // Remove + if (!copyAir) { + copy.setSourceMask(new ExistingBlockMask(this)); } - for (Map.Entry entry : delayed.entrySet()) { - setBlock(entry.getKey(), entry.getValue()); - ++affected; - } + // Then we need to copy the buffer to the world + BlockReplace replace = new BlockReplace(this, buffer); + RegionVisitor visitor = new RegionVisitor(buffer.asRegion(), replace); - return affected; + OperationQueue operation = new OperationQueue(copy, visitor); + Operations.completeLegacy(operation); + + return copy.getAffected(); } /** - * Move a cuboid region. + * Move the blocks in a region a certain direction. * - * @param region - * @param dir - * @param distance - * @param copyAir - * @param replace + * @param region the region to move + * @param dir the direction + * @param distance the distance to move + * @param copyAir true to copy air blocks + * @param replacement the replacement block to fill in after moving, or null to use air * @return number of blocks moved - * @throws MaxChangedBlocksException + * @throws MaxChangedBlocksException thrown if too many blocks are changed */ - public int moveCuboidRegion(Region region, Vector dir, int distance, - boolean copyAir, BaseBlock replace) - throws MaxChangedBlocksException { - int affected = 0; - - Vector shift = dir.multiply(distance); - Vector min = region.getMinimumPoint(); - Vector max = region.getMaximumPoint(); - - int minX = min.getBlockX(); - int minY = min.getBlockY(); - int minZ = min.getBlockZ(); - int maxX = max.getBlockX(); - int maxY = max.getBlockY(); - int maxZ = max.getBlockZ(); - - Vector newMin = min.add(shift); - Vector newMax = min.add(shift); - - Map delayed = new LinkedHashMap(); - - for (int x = minX; x <= maxX; ++x) { - for (int z = minZ; z <= maxZ; ++z) { - for (int y = minY; y <= maxY; ++y) { - Vector pos = new Vector(x, y, z); - BaseBlock block = getBlock(pos); - - if (!block.isAir() || copyAir) { - Vector newPos = pos.add(shift); - - delayed.put(newPos, getBlock(pos)); - - // Don't want to replace the old block if it's in - // the new area - if (x >= newMin.getBlockX() && x <= newMax.getBlockX() - && y >= newMin.getBlockY() - && y <= newMax.getBlockY() - && z >= newMin.getBlockZ() - && z <= newMax.getBlockZ()) { - } else { - setBlock(pos, replace); - } - } - } - } - } - - for (Map.Entry entry : delayed.entrySet()) { - setBlock(entry.getKey(), entry.getValue()); - ++affected; - } - - return affected; + public int moveCuboidRegion(Region region, Vector dir, int distance, boolean copyAir, BaseBlock replacement) throws MaxChangedBlocksException { + return moveRegion(region, dir, distance, copyAir, replacement); } /** * Drain nearby pools of water or lava. * - * @param pos - * @param radius + * @param origin the origin to drain from, which will search a 3x3 area + * @param radius the radius of the removal, where a value should be 0 or greater * @return number of blocks affected - * @throws MaxChangedBlocksException + * @throws MaxChangedBlocksException thrown if too many blocks are changed */ - public int drainArea(Vector pos, double radius) - throws MaxChangedBlocksException { - int affected = 0; + public int drainArea(Vector origin, double radius) throws MaxChangedBlocksException { + checkNotNull(origin); + checkArgument(radius >= 0, "radius >= 0 required"); - HashSet visited = new HashSet(); - Stack queue = new Stack(); + MaskIntersection mask = new MaskIntersection( + new BoundedHeightMask(0, getWorld().getMaxY()), + new RegionMask(new EllipsoidRegion(null, origin, new Vector(radius, radius, radius))), + getWorld().createLiquidMask()); - for (int x = pos.getBlockX() - 1; x <= pos.getBlockX() + 1; ++x) { - for (int z = pos.getBlockZ() - 1; z <= pos.getBlockZ() + 1; ++z) { - for (int y = pos.getBlockY() - 1; y <= pos.getBlockY() + 1; ++y) { - queue.push(new BlockVector(x, y, z)); - } + BlockReplace replace = new BlockReplace(this, new BlockPattern(new BaseBlock(BlockID.AIR))); + RecursiveVisitor visitor = new RecursiveVisitor(mask, replace); + + // Around the origin in a 3x3 block + for (BlockVector position : CuboidRegion.fromCenter(origin, 1)) { + if (mask.test(position)) { + visitor.visit(position); } } - while (!queue.empty()) { - BlockVector cur = queue.pop(); + Operations.completeLegacy(visitor); - int type = getBlockType(cur); - - // Check block type - if (type != BlockID.WATER && type != BlockID.STATIONARY_WATER - && type != BlockID.LAVA && type != BlockID.STATIONARY_LAVA) { - continue; - } - - // Don't want to revisit - if (visited.contains(cur)) { - continue; - } - - visited.add(cur); - - // Check radius - if (pos.distance(cur) > radius) { - continue; - } - - for (int x = cur.getBlockX() - 1; x <= cur.getBlockX() + 1; ++x) { - for (int z = cur.getBlockZ() - 1; z <= cur.getBlockZ() + 1; ++z) { - for (int y = cur.getBlockY() - 1; y <= cur.getBlockY() + 1; ++y) { - BlockVector newPos = new BlockVector(x, y, z); - - if (!cur.equals(newPos)) { - queue.push(newPos); - } - } - } - } - - if (setBlock(cur, new BaseBlock(BlockID.AIR))) { - ++affected; - } - } - - return affected; + return visitor.getAffected(); } /** - * Level water. + * Fix liquids so that they turn into stationary blocks and extend outward. * - * @param pos - * @param radius - * @param moving - * @param stationary + * @param origin the original position + * @param radius the radius to fix + * @param moving the block ID of the moving liquid + * @param stationary the block ID of the stationary liquid * @return number of blocks affected - * @throws MaxChangedBlocksException + * @throws MaxChangedBlocksException thrown if too many blocks are changed */ - public int fixLiquid(Vector pos, double radius, int moving, int stationary) - throws MaxChangedBlocksException { - int affected = 0; + public int fixLiquid(Vector origin, double radius, int moving, int stationary) throws MaxChangedBlocksException { + checkNotNull(origin); + checkArgument(radius >= 0, "radius >= 0 required"); - HashSet visited = new HashSet(); - Stack queue = new Stack(); + // Our origins can only be liquids + BlockMask liquidMask = new BlockMask( + this, + new BaseBlock(moving, -1), + new BaseBlock(stationary, -1)); - for (int x = pos.getBlockX() - 1; x <= pos.getBlockX() + 1; ++x) { - for (int z = pos.getBlockZ() - 1; z <= pos.getBlockZ() + 1; ++z) { - for (int y = pos.getBlockY() - 1; y <= pos.getBlockY() + 1; ++y) { - int type = getBlock(new Vector(x, y, z)).getType(); + // But we will also visit air blocks + MaskIntersection blockMask = + new MaskUnion(liquidMask, + new BlockMask( + this, + new BaseBlock(BlockID.AIR))); - // Check block type - if (type == moving || type == stationary) { - queue.push(new BlockVector(x, y, z)); - } - } + // There are boundaries that the routine needs to stay in + MaskIntersection mask = new MaskIntersection( + new BoundedHeightMask(0, Math.min(origin.getBlockY(), getWorld().getMaxY())), + new RegionMask(new EllipsoidRegion(null, origin, new Vector(radius, radius, radius))), + blockMask); + + BlockReplace replace = new BlockReplace(this, new BlockPattern(new BaseBlock(stationary))); + NonRisingVisitor visitor = new NonRisingVisitor(mask, replace); + + // Around the origin in a 3x3 block + for (BlockVector position : CuboidRegion.fromCenter(origin, 1)) { + if (liquidMask.test(position)) { + visitor.visit(position); } } - BaseBlock stationaryBlock = new BaseBlock(stationary); + Operations.completeLegacy(visitor); - while (!queue.empty()) { - BlockVector cur = queue.pop(); - - int type = getBlockType(cur); - - // Check block type - if (type != moving && type != stationary && type != BlockID.AIR) { - continue; - } - - // Don't want to revisit - if (visited.contains(cur)) { - continue; - } - - visited.add(cur); - - if (setBlock(cur, stationaryBlock)) { - ++affected; - } - - // Check radius - if (pos.distance(cur) > radius) { - continue; - } - - queue.push(cur.add(1, 0, 0).toBlockVector()); - queue.push(cur.add(-1, 0, 0).toBlockVector()); - queue.push(cur.add(0, 0, 1).toBlockVector()); - queue.push(cur.add(0, 0, -1).toBlockVector()); - } - - return affected; + return visitor.getAffected(); } /** @@ -2316,14 +1398,6 @@ public class EditSession { return affected; } - private static final double lengthSq(double x, double y, double z) { - return (x * x) + (y * y) + (z * z); - } - - private static final double lengthSq(double x, double z) { - return (x * x) + (z * z); - } - /** * Makes a pyramid. * @@ -2583,18 +1657,17 @@ public class EditSession { generator.setPlant(GardenPatchGenerator.getPumpkinPattern()); // In a region of the given radius - Region region = new CuboidRegion(position.add(-apothem, -5, -apothem), position.add(apothem, 10, apothem)); + FlatRegion region = new CuboidRegion( + getWorld(), // Causes clamping of Y range + position.add(-apothem, -5, -apothem), + position.add(apothem, 10, apothem)); + double density = 0.02; - // And we want to scatter them - GroundScatterFunction scatter = new GroundScatterFunction(this, generator); - scatter.setDensity(0.02); - scatter.setRange(region); - - // Generate those patches! - FlatRegionApplicator operation = new FlatRegionApplicator(region, scatter); - OperationHelper.completeLegacy(operation); - - return operation.getAffected(); + GroundFunction ground = new GroundFunction(new ExistingBlockMask(this), generator); + LayerVisitor visitor = new LayerVisitor(region, minimumBlockY(region), maximumBlockY(region), ground); + visitor.setMask(new NoiseFilter2D(new RandomNoise(), density)); + Operations.completeLegacy(visitor); + return ground.getAffected(); } /** @@ -2643,42 +1716,6 @@ public class EditSession { return affected; } - /** - * Makes a forest. - * - * @param it an iterator over the points within the region - * @param upperY the Y to start from (upperY >= lowerY), inclusive - * @param lowerY the Y to end at (upperY >= lowerY), inclusive - * @param density density of the forest - * @param treeGenerator the tree generator - * @return number of trees created - * @throws MaxChangedBlocksException - * @deprecated Use {@link com.sk89q.worldedit.generator.ForestGenerator} with a - * {@link com.sk89q.worldedit.operation.FlatRegionApplicator} - */ - @Deprecated - public int makeForest(Iterable it, int upperY, int lowerY, - double density, TreeGenerator treeGenerator) - throws WorldEditException { - - ForestGenerator generator = new ForestGenerator(this, treeGenerator); - - // And we want to scatter them - GroundScatterFunction scatter = new GroundScatterFunction(this, generator); - scatter.setDensity(density); - scatter.setRange(lowerY, upperY); - - int affected = 0; - - for (Vector2D pt : it) { - if (scatter.apply(pt)) { - affected++; - } - } - - return affected; - } - /** * Get the block distribution inside a region. * @@ -2873,15 +1910,6 @@ public class EditSession { return affected; } - private static final Vector[] recurseDirections = { - PlayerDirection.NORTH.vector(), - PlayerDirection.EAST.vector(), - PlayerDirection.SOUTH.vector(), - PlayerDirection.WEST.vector(), - PlayerDirection.UP.vector(), - PlayerDirection.DOWN.vector(), - }; - /** * Hollows out the region (Semi-well-defined for non-cuboid selections). * @@ -3122,16 +2150,6 @@ public class EditSession { return returnset; } - private int setBlocks(Set vset, Pattern pattern) - throws MaxChangedBlocksException { - - int affected = 0; - for (Vector v : vset) { - affected += setBlock(v, pattern) ? 1 : 0; - } - return affected; - } - private void recurseHollow(Region region, BlockVector origin, Set outside) { final LinkedList queue = new LinkedList(); queue.addLast(origin); @@ -3190,4 +2208,22 @@ public class EditSession { return shape.generate(this, biomeType, hollow); } + + private static final Vector[] recurseDirections = { + PlayerDirection.NORTH.vector(), + PlayerDirection.EAST.vector(), + PlayerDirection.SOUTH.vector(), + PlayerDirection.WEST.vector(), + PlayerDirection.UP.vector(), + PlayerDirection.DOWN.vector(), + }; + + private static final double lengthSq(double x, double y, double z) { + return (x * x) + (y * y) + (z * z); + } + + private static final double lengthSq(double x, double z) { + return (x * x) + (z * z); + } + } diff --git a/src/main/java/com/sk89q/worldedit/EditSessionFactory.java b/src/main/java/com/sk89q/worldedit/EditSessionFactory.java index 90beb7caa..420bfd8c5 100644 --- a/src/main/java/com/sk89q/worldedit/EditSessionFactory.java +++ b/src/main/java/com/sk89q/worldedit/EditSessionFactory.java @@ -1,51 +1,75 @@ +/* + * 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; -import com.sk89q.worldedit.bags.BlockBag; +import com.sk89q.worldedit.event.extent.EditSessionEvent; +import com.sk89q.worldedit.extent.inventory.BlockBag; +/** + * @deprecated To wrap {@link EditSession}s, please hook into {@link EditSessionEvent} + */ +@Deprecated public class EditSessionFactory { /** * Construct an edit session with a maximum number of blocks. * - * @param world - * @param maxBlocks + * @param world the world + * @param maxBlocks the maximum number of blocks that can be changed, or -1 to use no limit */ public EditSession getEditSession(LocalWorld world, int maxBlocks) { - return new EditSession(world, maxBlocks); + throw new IllegalArgumentException("This class is being removed"); } /** * Construct an edit session with a maximum number of blocks. * - * @param world - * @param maxBlocks - * @param player + * @param world the world + * @param maxBlocks the maximum number of blocks that can be changed, or -1 to use no limit + * @param player the player that the {@link EditSession} is for */ public EditSession getEditSession(LocalWorld world, int maxBlocks, LocalPlayer player) { - return this.getEditSession(world, maxBlocks); + throw new IllegalArgumentException("This class is being removed"); } /** * Construct an edit session with a maximum number of blocks and a block bag. * - * @param world - * @param maxBlocks - * @param blockBag + * @param world the world + * @param maxBlocks the maximum number of blocks that can be changed, or -1 to use no limit + * @param blockBag an optional {@link BlockBag} to use, otherwise null */ public EditSession getEditSession(LocalWorld world, int maxBlocks, BlockBag blockBag) { - return new EditSession(world, maxBlocks, blockBag); + throw new IllegalArgumentException("This class is being removed"); } /** * Construct an edit session with a maximum number of blocks and a block bag. * - * @param world - * @param maxBlocks - * @param blockBag - * @param player + * @param world the world + * @param maxBlocks the maximum number of blocks that can be changed, or -1 to use no limit + * @param blockBag an optional {@link BlockBag} to use, otherwise null + * @param player the player that the {@link EditSession} is for */ public EditSession getEditSession(LocalWorld world, int maxBlocks, BlockBag blockBag, LocalPlayer player) { - return this.getEditSession(world, maxBlocks, blockBag); + throw new IllegalArgumentException("This class is being removed"); } } diff --git a/src/main/java/com/sk89q/worldedit/LocalConfiguration.java b/src/main/java/com/sk89q/worldedit/LocalConfiguration.java index 5a3cd72a3..49d3bdb7f 100644 --- a/src/main/java/com/sk89q/worldedit/LocalConfiguration.java +++ b/src/main/java/com/sk89q/worldedit/LocalConfiguration.java @@ -25,7 +25,7 @@ import java.util.Set; import com.sk89q.worldedit.blocks.BlockID; import com.sk89q.worldedit.blocks.ItemID; -import com.sk89q.worldedit.snapshots.SnapshotRepository; +import com.sk89q.worldedit.world.snapshot.SnapshotRepository; /** * Represents WorldEdit's configuration. diff --git a/src/main/java/com/sk89q/worldedit/LocalPlayer.java b/src/main/java/com/sk89q/worldedit/LocalPlayer.java index 4fa98c7aa..b0121e28e 100644 --- a/src/main/java/com/sk89q/worldedit/LocalPlayer.java +++ b/src/main/java/com/sk89q/worldedit/LocalPlayer.java @@ -21,12 +21,12 @@ package com.sk89q.worldedit; import java.io.File; -import com.sk89q.worldedit.bags.BlockBag; +import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BlockID; import com.sk89q.worldedit.blocks.BlockType; import com.sk89q.worldedit.blocks.ItemID; -import com.sk89q.worldedit.cui.CUIEvent; +import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.util.TargetBlock; /** diff --git a/src/main/java/com/sk89q/worldedit/LocalSession.java b/src/main/java/com/sk89q/worldedit/LocalSession.java index 7e73d222d..591656914 100644 --- a/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -19,28 +19,26 @@ package com.sk89q.worldedit; -import java.util.Calendar; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; -import java.util.TimeZone; import com.sk89q.jchronic.Chronic; import com.sk89q.jchronic.Options; import com.sk89q.jchronic.utils.Span; import com.sk89q.jchronic.utils.Time; -import com.sk89q.worldedit.snapshots.Snapshot; -import com.sk89q.worldedit.tools.BrushTool; -import com.sk89q.worldedit.tools.SinglePickaxe; -import com.sk89q.worldedit.tools.BlockTool; -import com.sk89q.worldedit.tools.Tool; -import com.sk89q.worldedit.bags.BlockBag; -import com.sk89q.worldedit.cui.CUIRegion; -import com.sk89q.worldedit.cui.CUIEvent; -import com.sk89q.worldedit.cui.SelectionShapeEvent; +import com.sk89q.worldedit.command.tool.BlockTool; +import com.sk89q.worldedit.command.tool.BrushTool; +import com.sk89q.worldedit.command.tool.SinglePickaxe; +import com.sk89q.worldedit.command.tool.Tool; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.internal.cui.CUIEvent; +import com.sk89q.worldedit.internal.cui.CUIRegion; +import com.sk89q.worldedit.internal.cui.SelectionShapeEvent; import com.sk89q.worldedit.masks.Mask; -import com.sk89q.worldedit.regions.CuboidRegionSelector; +import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.RegionSelector; +import com.sk89q.worldedit.session.request.Request; +import com.sk89q.worldedit.world.snapshot.Snapshot; + +import java.util.*; /** * An instance of this represents the WorldEdit session of a user. A session @@ -704,6 +702,7 @@ public class LocalSession { .getEditSession(player.isPlayer() ? player.getWorld() : null, getBlockChangeLimit(), blockBag, player); editSession.setFastMode(fastMode); + Request.request().setEditSession(editSession); if (mask != null) { mask.prepare(this, player, null); } diff --git a/src/main/java/com/sk89q/worldedit/LocalWorld.java b/src/main/java/com/sk89q/worldedit/LocalWorld.java index 449faa681..9ce353181 100644 --- a/src/main/java/com/sk89q/worldedit/LocalWorld.java +++ b/src/main/java/com/sk89q/worldedit/LocalWorld.java @@ -19,31 +19,26 @@ package com.sk89q.worldedit; -import java.util.PriorityQueue; -import java.util.Random; - -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.blocks.BaseItemStack; -import com.sk89q.worldedit.blocks.BlockID; -import com.sk89q.worldedit.blocks.BlockType; -import com.sk89q.worldedit.blocks.ChestBlock; -import com.sk89q.worldedit.blocks.DispenserBlock; -import com.sk89q.worldedit.blocks.FurnaceBlock; -import com.sk89q.worldedit.blocks.MobSpawnerBlock; -import com.sk89q.worldedit.blocks.NoteBlock; -import com.sk89q.worldedit.blocks.SignBlock; -import com.sk89q.worldedit.blocks.SkullBlock; -import com.sk89q.worldedit.foundation.Block; -import com.sk89q.worldedit.foundation.World; +import com.sk89q.worldedit.blocks.*; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.function.mask.BlockMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.TreeGenerator; +import javax.annotation.Nullable; +import java.util.PriorityQueue; +import java.util.Random; + /** * Represents a world. * * @author sk89q */ -public abstract class LocalWorld implements World { +public abstract class LocalWorld implements World, Extent { + /** * Named flags to use as parameters to {@link LocalWorld#killMobs(Vector, double, int)} */ @@ -97,6 +92,7 @@ public abstract class LocalWorld implements World { * @param pt * @return */ + @Deprecated public abstract int getBlockType(Vector pt); /** @@ -166,6 +162,7 @@ public abstract class LocalWorld implements World { * @param pt * @return */ + @Deprecated public abstract int getBlockData(Vector pt); /** @@ -528,9 +525,14 @@ public abstract class LocalWorld implements World { public int killEntities(LocalEntity... entities) { return 0; } + + @Override + public boolean setBlock(Vector pt, BaseBlock block) { + return setBlock(pt, block, true); + } @Override - public boolean setBlock(Vector pt, Block block, boolean notifyAdjacent) { + public boolean setBlock(Vector pt, BaseBlock block, boolean notifyAdjacent) { boolean successful; // Default implementation will call the old deprecated methods @@ -547,6 +549,11 @@ public abstract class LocalWorld implements World { return successful; } + @Override + public BaseBlock getLazyBlock(Vector position) { + return getBlock(position); + } + @Override public BaseBlock getBlock(Vector pt) { checkLoadedChunk(pt); @@ -603,4 +610,34 @@ public abstract class LocalWorld implements World { return new BaseBlock(type, data); } } + + /** + * Create a mask that matches all liquids. + *

+ * Implementations should override this so that custom liquids are supported. + * + * @return a mask + */ + public Mask createLiquidMask() { + return new BlockMask(this, + new BaseBlock(BlockID.STATIONARY_LAVA, -1), + new BaseBlock(BlockID.LAVA, -1), + new BaseBlock(BlockID.STATIONARY_WATER, -1), + new BaseBlock(BlockID.WATER, -1)); + } + + @Override + public Vector getMaximumPoint() { + return new Vector(30000000, 30000000, 30000000); + } + + @Override + public Vector getMinimumPoint() { + return new Vector(-30000000, -30000000, -30000000); + } + + @Override + public @Nullable Operation commit() { + return null; + } } diff --git a/src/main/java/com/sk89q/worldedit/WorldEdit.java b/src/main/java/com/sk89q/worldedit/WorldEdit.java index 8da24d03c..fba9db2e9 100644 --- a/src/main/java/com/sk89q/worldedit/WorldEdit.java +++ b/src/main/java/com/sk89q/worldedit/WorldEdit.java @@ -1,7 +1,7 @@ -// $Id$ /* - * WorldEdit - * Copyright (C) 2010 sk89q and contributors + * 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 @@ -15,155 +15,78 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -*/ + */ package com.sk89q.worldedit; -import java.io.DataInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; +import com.sk89q.minecraft.util.commands.*; +import com.sk89q.minecraft.util.commands.Console; +import com.sk89q.util.StringUtil; +import com.sk89q.worldedit.CuboidClipboard.FlipDirection; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockType; +import com.sk89q.worldedit.blocks.ItemType; +import com.sk89q.worldedit.command.*; +import com.sk89q.worldedit.command.tool.*; +import com.sk89q.worldedit.event.extent.EditSessionEvent; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.registry.BlockRegistry; +import com.sk89q.worldedit.extension.registry.MaskRegistry; +import com.sk89q.worldedit.extension.registry.PatternRegistry; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.function.mask.Masks; +import com.sk89q.worldedit.function.pattern.Patterns; +import com.sk89q.worldedit.internal.InternalEditSessionFactory; +import com.sk89q.worldedit.masks.Mask; +import com.sk89q.worldedit.patterns.Pattern; +import com.sk89q.worldedit.regions.selector.RegionSelector; +import com.sk89q.worldedit.scripting.CraftScriptContext; +import com.sk89q.worldedit.scripting.CraftScriptEngine; +import com.sk89q.worldedit.scripting.RhinoCraftScriptEngine; +import com.sk89q.worldedit.session.SessionManager; +import com.sk89q.worldedit.session.request.Request; +import com.sk89q.worldedit.util.LogFormat; +import com.sk89q.worldedit.util.eventbus.EventBus; + +import javax.script.ScriptException; +import java.io.*; import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.logging.FileHandler; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; -import javax.script.ScriptException; - -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandPermissionsException; -import com.sk89q.minecraft.util.commands.CommandUsageException; -import com.sk89q.minecraft.util.commands.CommandsManager; -import com.sk89q.minecraft.util.commands.Console; -import com.sk89q.minecraft.util.commands.Logging; -import com.sk89q.minecraft.util.commands.MissingNestedCommandException; -import com.sk89q.minecraft.util.commands.SimpleInjector; -import com.sk89q.minecraft.util.commands.UnhandledCommandException; -import com.sk89q.minecraft.util.commands.WrappedCommandException; -import com.sk89q.util.StringUtil; -import com.sk89q.worldedit.CuboidClipboard.FlipDirection; -import com.sk89q.worldedit.bags.BlockBag; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.blocks.BlockType; -import com.sk89q.worldedit.blocks.ClothColor; -import com.sk89q.worldedit.blocks.ItemType; -import com.sk89q.worldedit.blocks.MobSpawnerBlock; -import com.sk89q.worldedit.blocks.NoteBlock; -import com.sk89q.worldedit.blocks.SignBlock; -import com.sk89q.worldedit.blocks.SkullBlock; -import com.sk89q.worldedit.commands.BiomeCommands; -import com.sk89q.worldedit.commands.ChunkCommands; -import com.sk89q.worldedit.commands.ClipboardCommands; -import com.sk89q.worldedit.commands.GeneralCommands; -import com.sk89q.worldedit.commands.GenerationCommands; -import com.sk89q.worldedit.commands.HistoryCommands; -import com.sk89q.worldedit.commands.InsufficientArgumentsException; -import com.sk89q.worldedit.commands.NavigationCommands; -import com.sk89q.worldedit.commands.RegionCommands; -import com.sk89q.worldedit.commands.ScriptingCommands; -import com.sk89q.worldedit.commands.SelectionCommands; -import com.sk89q.worldedit.commands.SnapshotUtilCommands; -import com.sk89q.worldedit.commands.ToolCommands; -import com.sk89q.worldedit.commands.ToolUtilCommands; -import com.sk89q.worldedit.commands.UtilityCommands; -import com.sk89q.worldedit.masks.BiomeTypeMask; -import com.sk89q.worldedit.masks.BlockMask; -import com.sk89q.worldedit.masks.CombinedMask; -import com.sk89q.worldedit.masks.DynamicRegionMask; -import com.sk89q.worldedit.masks.ExistingBlockMask; -import com.sk89q.worldedit.masks.InvertedMask; -import com.sk89q.worldedit.masks.Mask; -import com.sk89q.worldedit.masks.RandomMask; -import com.sk89q.worldedit.masks.RegionMask; -import com.sk89q.worldedit.masks.SolidBlockMask; -import com.sk89q.worldedit.masks.UnderOverlayMask; -import com.sk89q.worldedit.patterns.BlockChance; -import com.sk89q.worldedit.patterns.ClipboardPattern; -import com.sk89q.worldedit.patterns.Pattern; -import com.sk89q.worldedit.patterns.RandomFillPattern; -import com.sk89q.worldedit.patterns.SingleBlockPattern; -import com.sk89q.worldedit.regions.RegionSelector; -import com.sk89q.worldedit.scripting.CraftScriptContext; -import com.sk89q.worldedit.scripting.CraftScriptEngine; -import com.sk89q.worldedit.scripting.RhinoCraftScriptEngine; -import com.sk89q.worldedit.tools.BlockTool; -import com.sk89q.worldedit.tools.DoubleActionBlockTool; -import com.sk89q.worldedit.tools.DoubleActionTraceTool; -import com.sk89q.worldedit.tools.Tool; -import com.sk89q.worldedit.tools.TraceTool; +import static com.google.common.base.Preconditions.checkNotNull; /** - * This class is the main entry point for WorldEdit. All events are routed - * to an instance of this controller for processing by WorldEdit. For - * integrating WorldEdit in other platforms, an instance of this class - * should be created and events should be redirected to it. - * - * @author sk89q + * The current instance of WorldEdit. */ public class WorldEdit { - /** - * Logger for debugging. - */ + public static final Logger logger = Logger.getLogger("Minecraft.WorldEdit"); public final Logger commandLogger = Logger.getLogger("Minecraft.WorldEdit.CommandLogger"); - /** - * Holds the current instance of this class, for static access - */ private static WorldEdit instance; - - /** - * Holds WorldEdit's version. - */ private static String version; - /** - * Interface to the server. - */ private final ServerInterface server; - - /** - * Configuration. This is a subclass. - */ private final LocalConfiguration config; - - /** - * List of commands. - */ private final CommandsManager commands; - - /** - * Holds the factory responsible for the creation of edit sessions - */ - private EditSessionFactory editSessionFactory = new EditSessionFactory(); + private final EventBus eventBus = new EventBus(); + private final EditSessionFactory editSessionFactory = new InternalEditSessionFactory(eventBus); + private final SessionManager sessions = new SessionManager(this); - /** - * Stores a list of WorldEdit sessions, keyed by players' names. Sessions - * persist only for the user's session. On disconnect, the session will be - * removed. Sessions are created only when they are needed and those - * without any WorldEdit abilities or never use WorldEdit in a session will - * not have a session object generated for them. - */ - private final HashMap sessions = new HashMap(); + private final BlockRegistry blockRegistry = new BlockRegistry(this); + private final MaskRegistry maskRegistry = new MaskRegistry(this); + private final PatternRegistry patternRegistry = new PatternRegistry(this); - /** - * Initialize statically. - */ static { getVersion(); } /** - * Construct an instance of the plugin + * Construct an instance of WorldEdit. * * @param server * @param config @@ -291,364 +214,129 @@ public class WorldEdit { } /** - * Gets the LocalSession for a player name if it exists + * Get the event bus for WorldEdit. * - * @param player - * @return The session for the player, if it exists + * @return the event bus */ + public EventBus getEventBus() { + return eventBus; + } + + /** + * Get the block registry from which new {@link BaseBlock}s can be + * constructed. + * + * @return the block registry + */ + public BlockRegistry getBlockRegistry() { + return blockRegistry; + } + + /** + * Get the mask registry from which new {@link com.sk89q.worldedit.function.mask.Mask}s + * can be constructed. + * + * @return the mask registry + */ + public MaskRegistry getMaskRegistry() { + return maskRegistry; + } + + /** + * Get the pattern registry from which new {@link com.sk89q.worldedit.function.pattern.Pattern}s + * can be constructed. + * + * @return the pattern registry + */ + public PatternRegistry getPatternRegistry() { + return patternRegistry; + } + + /** + * Return the session manager. + * + * @return the session manager + */ + public SessionManager getSessionManager() { + return sessions; + } + + /** + * @deprecated Use {@link #getSessionManager()} + */ + @Deprecated public LocalSession getSession(String player) { + return sessions.findByName(player); + } + + /** + * @deprecated use {@link #getSessionManager()} + */ + @Deprecated + public LocalSession getSession(LocalPlayer player) { return sessions.get(player); } /** - * Gets the WorldEdit session for a player. - * - * @param player - * @return + * @deprecated use {@link #getSessionManager()} */ - public LocalSession getSession(LocalPlayer player) { - LocalSession session; - - synchronized (sessions) { - if (sessions.containsKey(player.getName())) { - session = sessions.get(player.getName()); - } else { - session = new LocalSession(config); - session.setBlockChangeLimit(config.defaultChangeLimit); - // Remember the session - sessions.put(player.getName(), session); - } - - // Set the limit on the number of blocks that an operation can - // change at once, or don't if the player has an override or there - // is no limit. There is also a default limit - int currentChangeLimit = session.getBlockChangeLimit(); - - if (!player.hasPermission("worldedit.limit.unrestricted") - && config.maxChangeLimit > -1) { - - // If the default limit is infinite but there is a maximum - // limit, make sure to not have it be overridden - if (config.defaultChangeLimit < 0) { - if (currentChangeLimit < 0 || currentChangeLimit > config.maxChangeLimit) { - session.setBlockChangeLimit(config.maxChangeLimit); - } - } else { - // Bound the change limit - int maxChangeLimit = config.maxChangeLimit; - if (currentChangeLimit == -1 || currentChangeLimit > maxChangeLimit) { - session.setBlockChangeLimit(maxChangeLimit); - } - } - } - - // Have the session use inventory if it's enabled and the player - // doesn't have an override - session.setUseInventory(config.useInventory - && !(config.useInventoryOverride - && (player.hasPermission("worldedit.inventory.unrestricted") - || (config.useInventoryCreativeOverride && player.hasCreativeMode())))); - } - - return session; + @Deprecated + public void removeSession(LocalPlayer player) { + sessions.remove(player); } /** - * Returns true if the player has a session. - * - * @param player - * @return + * @deprecated use {@link #getSessionManager()} */ - public boolean hasSession(LocalPlayer player) { - // TODO: If this is indeed used in multiple threads, we should use Collections.synchronizedMap here to simplify things and exclude sources of error. - synchronized (sessions) { - return sessions.containsKey(player.getName()); - } + @Deprecated + public void clearSessions() { + sessions.clear(); } - public BaseBlock getBlock(LocalPlayer player, String arg, boolean allAllowed) - throws WorldEditException { + /** + * @deprecated use {@link #getSessionManager()} + */ + @Deprecated + public boolean hasSession(LocalPlayer player) { + return sessions.contains(player); + } + + /** + * @deprecated Use {@link #getBlockRegistry()} and {@link BlockRegistry#parseFromInput(String, ParserContext)} + */ + @Deprecated + public BaseBlock getBlock(LocalPlayer player, String arg, boolean allAllowed) throws WorldEditException { return getBlock(player, arg, allAllowed, false); } /** - * Get an item ID from an item name or an item ID number. - * - * @param player - * @param arg - * @param allAllowed true to ignore blacklists - * @param allowNoData return -1 for data if no data was given. - * @return - * @throws UnknownItemException - * @throws DisallowedItemException + * @deprecated Use {@link #getBlockRegistry()} and {@link BlockRegistry#parseFromInput(String, ParserContext)} */ - public BaseBlock getBlock(LocalPlayer player, String arg, - boolean allAllowed, boolean allowNoData) - throws WorldEditException { - BlockType blockType; - arg = arg.replace("_", " "); - arg = arg.replace(";", "|"); - String[] blockAndExtraData = arg.split("\\|"); - String[] typeAndData = blockAndExtraData[0].split(":", 2); - String testID = typeAndData[0]; - - int blockId = -1; - - int data = -1; - - boolean parseDataValue = true; - if ("hand".equalsIgnoreCase(testID)) { - // Get the block type from the item in the user's hand. - final BaseBlock blockInHand = player.getBlockInHand(); - if (blockInHand.getClass() != BaseBlock.class) { - return blockInHand; - } - - blockId = blockInHand.getId(); - blockType = BlockType.fromID(blockId); - data = blockInHand.getData(); - } else if ("pos1".equalsIgnoreCase(testID)) { - // Get the block type from the "primary position" - final LocalWorld world = player.getWorld(); - final BlockVector primaryPosition = getSession(player).getRegionSelector(world).getPrimaryPosition(); - final BaseBlock blockInHand = world.getBlock(primaryPosition); - if (blockInHand.getClass() != BaseBlock.class) { - return blockInHand; - } - - blockId = blockInHand.getId(); - blockType = BlockType.fromID(blockId); - data = blockInHand.getData(); - } else { - // Attempt to parse the item ID or otherwise resolve an item/block - // name to its numeric ID - try { - blockId = Integer.parseInt(testID); - blockType = BlockType.fromID(blockId); - } catch (NumberFormatException e) { - blockType = BlockType.lookup(testID); - if (blockType == null) { - int t = server.resolveItem(testID); - if (t > 0) { - blockType = BlockType.fromID(t); // Could be null - blockId = t; - } - } - } - - if (blockId == -1 && blockType == null) { - // Maybe it's a cloth - ClothColor col = ClothColor.lookup(testID); - if (col == null) { - throw new UnknownItemException(arg); - } - - blockType = BlockType.CLOTH; - data = col.getID(); - - // Prevent overriding the data value - parseDataValue = false; - } - - // Read block ID - if (blockId == -1) { - blockId = blockType.getID(); - } - - if (!player.getWorld().isValidBlockType(blockId)) { - throw new UnknownItemException(arg); - } - } - - if (!allowNoData && data == -1) { - // No wildcards allowed => eliminate them. - data = 0; - } - - if (parseDataValue) { // Block data not yet detected - // Parse the block data (optional) - try { - if (typeAndData.length > 1 && typeAndData[1].length() > 0) { - data = Integer.parseInt(typeAndData[1]); - } - - if (data > 15) { - throw new InvalidItemException(arg, "Invalid data value '" + typeAndData[1] + "'"); - } - - if (data < 0 && !(allAllowed && data == -1)) { - data = 0; - } - } catch (NumberFormatException e) { - if (blockType == null) { - throw new InvalidItemException(arg, "Unknown data value '" + typeAndData[1] + "'"); - } - - switch (blockType) { - case CLOTH: - case STAINED_CLAY: - case CARPET: - ClothColor col = ClothColor.lookup(typeAndData[1]); - if (col == null) { - throw new InvalidItemException(arg, "Unknown cloth color '" + typeAndData[1] + "'"); - } - - data = col.getID(); - break; - - case STEP: - case DOUBLE_STEP: - BlockType dataType = BlockType.lookup(typeAndData[1]); - - if (dataType == null) { - throw new InvalidItemException(arg, "Unknown step type '" + typeAndData[1] + "'"); - } - - switch (dataType) { - case STONE: - data = 0; - break; - case SANDSTONE: - data = 1; - break; - case WOOD: - data = 2; - break; - case COBBLESTONE: - data = 3; - break; - case BRICK: - data = 4; - break; - case STONE_BRICK: - data = 5; - break; - case NETHER_BRICK: - data = 6; - break; - case QUARTZ_BLOCK: - data = 7; - break; - - default: - throw new InvalidItemException(arg, "Invalid step type '" + typeAndData[1] + "'"); - } - break; - - default: - throw new InvalidItemException(arg, "Unknown data value '" + typeAndData[1] + "'"); - } - } - } - - // Check if the item is allowed - if (!allAllowed && !player.hasPermission("worldedit.anyblock") && config.disallowedBlocks.contains(blockId)) { - throw new DisallowedItemException(arg); - } - - if (blockType == null) { - return new BaseBlock(blockId, data); - } - - switch (blockType) { - case SIGN_POST: - case WALL_SIGN: - // Allow special sign text syntax - String[] text = new String[4]; - text[0] = blockAndExtraData.length > 1 ? blockAndExtraData[1] : ""; - text[1] = blockAndExtraData.length > 2 ? blockAndExtraData[2] : ""; - text[2] = blockAndExtraData.length > 3 ? blockAndExtraData[3] : ""; - text[3] = blockAndExtraData.length > 4 ? blockAndExtraData[4] : ""; - return new SignBlock(blockType.getID(), data, text); - - case MOB_SPAWNER: - // Allow setting mob spawn type - if (blockAndExtraData.length > 1) { - String mobName = blockAndExtraData[1]; - for (MobType mobType : MobType.values()) { - if (mobType.getName().toLowerCase().equals(mobName.toLowerCase())) { - mobName = mobType.getName(); - break; - } - } - if (!server.isValidMobType(mobName)) { - throw new InvalidItemException(arg, "Unknown mob type '" + mobName + "'"); - } - return new MobSpawnerBlock(data, mobName); - } else { - return new MobSpawnerBlock(data, MobType.PIG.getName()); - } - - case NOTE_BLOCK: - // Allow setting note - if (blockAndExtraData.length <= 1) { - return new NoteBlock(data, (byte) 0); - } - - byte note = Byte.parseByte(blockAndExtraData[1]); - if (note < 0 || note > 24) { - throw new InvalidItemException(arg, "Out of range note value: '" + blockAndExtraData[1] + "'"); - } - - return new NoteBlock(data, note); - - case HEAD: - // allow setting type/player/rotation - if (blockAndExtraData.length <= 1) { - return new SkullBlock(data); - } - - byte rot = 0; - String type = ""; - try { - rot = Byte.parseByte(blockAndExtraData[1]); - } catch (NumberFormatException e) { - type = blockAndExtraData[1]; - if (blockAndExtraData.length > 2) { - try { - rot = Byte.parseByte(blockAndExtraData[2]); - } catch (NumberFormatException e2) { - throw new InvalidItemException(arg, "Second part of skull metadata should be a number."); - } - } - } - byte skullType = 0; - // type is either the mob type or the player name - // sorry for the four minecraft accounts named "skeleton", "wither", "zombie", or "creeper" - if (!type.isEmpty()) { - if (type.equalsIgnoreCase("skeleton")) skullType = 0; - else if (type.equalsIgnoreCase("wither")) skullType = 1; - else if (type.equalsIgnoreCase("zombie")) skullType = 2; - else if (type.equalsIgnoreCase("creeper")) skullType = 4; - else skullType = 3; - } - if (skullType == 3) { - return new SkullBlock(data, rot, type.replace(" ", "_")); // valid MC usernames - } else { - return new SkullBlock(data, skullType, rot); - } - - default: - return new BaseBlock(blockId, data); - } + @Deprecated + public BaseBlock getBlock(LocalPlayer player, String arg, boolean allAllowed, boolean allowNoData) throws WorldEditException { + ParserContext context = new ParserContext(); + context.setPlayer(player); + context.setWorld(player.getWorld()); + context.setSession(getSession(player)); + context.setRestricted(!allAllowed); + context.setPreferringWildcard(allowNoData); + return getBlockRegistry().parseFromInput(arg, context); } /** - * Get a block. - * - * @param player - * @param id - * @return - * @throws UnknownItemException - * @throws DisallowedItemException + * @deprecated Use {@link #getBlockRegistry()} and {@link BlockRegistry#parseFromInput(String, ParserContext)} */ - public BaseBlock getBlock(LocalPlayer player, String id) - throws WorldEditException { + @Deprecated + public BaseBlock getBlock(LocalPlayer player, String id) throws WorldEditException { return getBlock(player, id, false); } - public Set getBlocks(LocalPlayer player, String list, boolean allAllowed, boolean allowNoData) - throws WorldEditException { + /** + * @deprecated Use {@link #getBlockRegistry()} and {@link BlockRegistry#parseFromListInput(String, ParserContext)} + */ + @Deprecated + @SuppressWarnings("deprecation") + public Set getBlocks(LocalPlayer player, String list, boolean allAllowed, boolean allowNoData) throws WorldEditException { String[] items = list.split(","); Set blocks = new HashSet(); for (String id : items) { @@ -657,182 +345,30 @@ public class WorldEdit { return blocks; } - public Set getBlocks(LocalPlayer player, String list, boolean allAllowed) - throws WorldEditException { + /** + * @deprecated Use {@link #getBlockRegistry()} and {@link BlockRegistry#parseFromInput(String, ParserContext)} + */ + @Deprecated + @SuppressWarnings("deprecation") + public Set getBlocks(LocalPlayer player, String list, boolean allAllowed) throws WorldEditException { return getBlocks(player, list, allAllowed, false); } - public Set getBlocks(LocalPlayer player, String list) - throws WorldEditException { + /** + * @deprecated Use {@link #getBlockRegistry()} and {@link BlockRegistry#parseFromListInput(String, ParserContext)} + */ + @Deprecated + @SuppressWarnings("deprecation") + public Set getBlocks(LocalPlayer player, String list) throws WorldEditException { return getBlocks(player, list, false); } /** - * Returns a Pattern corresponding to the specified pattern string, - * as given by the player on the command line. - * - * @param player - * @param patternString - * @return pattern - * @throws UnknownItemException - * @throws DisallowedItemException + * @deprecated Use {@link #getBlockRegistry()} and {@link BlockRegistry#parseFromListInput(String, ParserContext)} */ - public Pattern getBlockPattern(LocalPlayer player, String patternString) - throws WorldEditException { - - String[] items = patternString.split(","); - - // Handle special block pattern types - if (patternString.charAt(0) == '#') { - if (!patternString.equals("#clipboard") && !patternString.equals("#copy")) { - throw new UnknownItemException(patternString); - } - - LocalSession session = getSession(player); - - try { - return new ClipboardPattern(session.getClipboard()); - } catch (EmptyClipboardException e) { - player.printError("Copy a selection first with //copy."); - throw new UnknownItemException("#clipboard"); - } - } - - // If it's only one block, then just return that single one - if (items.length == 1) { - return new SingleBlockPattern(getBlock(player, items[0])); - } - - List blockChances = new ArrayList(); - - for (String s : items) { - BaseBlock block; - - double chance; - - // Parse special percentage syntax - if (s.matches("[0-9]+(\\.[0-9]*)?%.*")) { - String[] p = s.split("%"); - if (p.length < 2) { - throw new UnknownItemException(s); - } else { - chance = Double.parseDouble(p[0]); - block = getBlock(player, p[1]); - } - } else { - chance = 1; - block = getBlock(player, s); - } - - blockChances.add(new BlockChance(block, chance)); - } - - return new RandomFillPattern(blockChances); - } - - /** - * Get a block mask. Block masks are used to determine which - * blocks to include when replacing. - * - * @param player - * @param session - * @param maskString - * @return - * @throws WorldEditException - */ - public Mask getBlockMask(LocalPlayer player, LocalSession session, - String maskString) throws WorldEditException { - List masks = new ArrayList(); - - for (String component : maskString.split(" ")) { - if (component.length() == 0) { - continue; - } - - Mask current = getBlockMaskComponent(player, session, masks, component); - - masks.add(current); - } - - switch (masks.size()) { - case 0: - return null; - - case 1: - return masks.get(0); - - default: - return new CombinedMask(masks); - } - } - - private Mask getBlockMaskComponent(LocalPlayer player, LocalSession session, List masks, String component) throws WorldEditException { - final char firstChar = component.charAt(0); - switch (firstChar) { - case '#': - if (component.equalsIgnoreCase("#existing")) { - return new ExistingBlockMask(); - } else if (component.equalsIgnoreCase("#solid")) { - return new SolidBlockMask(); - } else if (component.equalsIgnoreCase("#dregion") - || component.equalsIgnoreCase("#dselection") - || component.equalsIgnoreCase("#dsel")) { - return new DynamicRegionMask(); - } else if (component.equalsIgnoreCase("#selection") - || component.equalsIgnoreCase("#region") - || component.equalsIgnoreCase("#sel")) { - return new RegionMask(session.getSelection(player.getWorld())); - } else { - throw new UnknownItemException(component); - } - - case '>': - case '<': - Mask submask; - if (component.length() > 1) { - submask = getBlockMaskComponent(player, session, masks, component.substring(1)); - } else { - submask = new ExistingBlockMask(); - } - return new UnderOverlayMask(submask, firstChar == '>'); - - case '$': - Set biomes = new HashSet(); - String[] biomesList = component.substring(1).split(","); - for (String biomeName : biomesList) { - BiomeType biome = server.getBiomes().get(biomeName); - biomes.add(biome); - } - return new BiomeTypeMask(biomes); - - case '%': - int i = Integer.parseInt(component.substring(1)); - return new RandomMask(((double) i) / 100); - - case '!': - if (component.length() > 1) { - return new InvertedMask(getBlockMaskComponent(player, session, masks, component.substring(1))); - } - - default: - return new BlockMask(getBlocks(player, component, true, true)); - } - } - - /** - * Get a list of blocks as a set. - * - * @param player - * @param list - * @param allBlocksAllowed - * @return set - * @throws UnknownItemException - * @throws DisallowedItemException - */ - public Set getBlockIDs(LocalPlayer player, - String list, boolean allBlocksAllowed) - throws WorldEditException { - + @Deprecated + @SuppressWarnings("deprecation") + public Set getBlockIDs(LocalPlayer player, String list, boolean allBlocksAllowed) throws WorldEditException { String[] items = list.split(","); Set blocks = new HashSet(); for (String s : items) { @@ -841,6 +377,32 @@ public class WorldEdit { return blocks; } + /** + * @deprecated Use {@link #getPatternRegistry()} and {@link BlockRegistry#parseFromInput(String, ParserContext)} + */ + @Deprecated + @SuppressWarnings("deprecation") + public Pattern getBlockPattern(LocalPlayer player, String input) throws WorldEditException { + ParserContext context = new ParserContext(); + context.setPlayer(player); + context.setWorld(player.getWorld()); + context.setSession(getSession(player)); + return Patterns.wrap(getPatternRegistry().parseFromInput(input, context)); + } + + /** + * @deprecated Use {@link #getMaskRegistry()} ()} and {@link MaskRegistry#parseFromInput(String, ParserContext)} + */ + @Deprecated + @SuppressWarnings("deprecation") + public Mask getBlockMask(LocalPlayer player, LocalSession session, String input) throws WorldEditException { + ParserContext context = new ParserContext(); + context.setPlayer(player); + context.setWorld(player.getWorld()); + context.setSession(session); + return Masks.wrap(getMaskRegistry().parseFromInput(input, context)); + } + /** * Gets the path to a file. This method will check to see if the filename * has valid characters and has an extension. It also prevents directory @@ -1153,26 +715,6 @@ public class WorldEdit { } } - /** - * Remove a session. - * - * @param player - */ - public void removeSession(LocalPlayer player) { - synchronized (sessions) { - sessions.remove(player.getName()); - } - } - - /** - * Remove all sessions. - */ - public void clearSessions() { - synchronized (sessions) { - sessions.clear(); - } - } - /** * Flush a block bag's changes to a player. * @@ -1231,8 +773,9 @@ public class WorldEdit { } /** + * Handle a disconnection. * - * @param player + * @param player the player */ @Deprecated public void handleDisconnect(LocalPlayer player) { @@ -1240,42 +783,28 @@ public class WorldEdit { } /** + * Mark for expiration of the session. * - * @param player + * @param player the player */ public void markExpire(LocalPlayer player) { - synchronized (sessions) { - LocalSession session = sessions.get(player.getName()); - if (session != null) { - session.update(); - } - } + sessions.markforExpiration(player); } /** * Forget a player. * - * @param player + * @param player the player */ public void forgetPlayer(LocalPlayer player) { - removeSession(player); + sessions.remove(player); } /* * Flush expired sessions. */ public void flushExpiredSessions(SessionCheck checker) { - synchronized (sessions) { - Iterator> it = sessions.entrySet().iterator(); - - while (it.hasNext()) { - Map.Entry entry = it.next(); - if (entry.getValue().hasExpired() - && !checker.isOnlinePlayer(entry.getKey())) { - it.remove(); - } - } - } + sessions.removeExpired(checker); } /** @@ -1444,6 +973,8 @@ public class WorldEdit { * @return whether the command was processed */ public boolean handleCommand(LocalPlayer player, String[] split) { + Request.reset(); + try { split = commandDetection(split); @@ -1547,6 +1078,8 @@ public class WorldEdit { } public String[] commandDetection(String[] split) { + Request.reset(); + split[0] = split[0].substring(1); // Quick script shortcut @@ -1579,8 +1112,9 @@ public class WorldEdit { * @param args * @throws WorldEditException */ - public void runScript(LocalPlayer player, File f, String[] args) - throws WorldEditException { + public void runScript(LocalPlayer player, File f, String[] args) throws WorldEditException { + Request.reset(); + String filename = f.getPath(); int index = filename.lastIndexOf("."); String ext = filename.substring(index + 1, filename.length()); @@ -1679,25 +1213,24 @@ public class WorldEdit { } /** - * Get the edit session factory - * - * @return + * Get a factory for {@link EditSession}s. */ public EditSessionFactory getEditSessionFactory() { - return this.editSessionFactory; + return editSessionFactory; } /** - * Set the edit session factory - * - * @param factory + * @deprecated EditSessionFactories are no longer used. Please register an {@link EditSessionEvent} event + * with the event bus in order to override or catch changes to the world */ + @Deprecated public void setEditSessionFactory(EditSessionFactory factory) { - if (factory == null) { - throw new IllegalArgumentException("New EditSessionFactory may not be null"); - } - logger.info("Accepted EditSessionFactory of type " + factory.getClass().getName() + " from " + factory.getClass().getPackage().getName()); - this.editSessionFactory = factory; + checkNotNull(factory); + logger.severe("Got request to set EditSessionFactory of type " + + factory.getClass().getName() + " from " + factory.getClass().getPackage().getName() + + " but EditSessionFactories have been removed in favor of extending EditSession's extents.\n\n" + + "This may mean that any block logger / intercepters addons/plugins/mods that you have installed will not " + + "intercept WorldEdit's changes! Please notify the maintainer of the other addon about this."); } /** diff --git a/src/main/java/com/sk89q/worldedit/WorldEditException.java b/src/main/java/com/sk89q/worldedit/WorldEditException.java index 82ddcae6d..6520123c1 100644 --- a/src/main/java/com/sk89q/worldedit/WorldEditException.java +++ b/src/main/java/com/sk89q/worldedit/WorldEditException.java @@ -1,7 +1,7 @@ -// $Id$ /* - * WorldEdit - * Copyright (C) 2010 sk89q and contributors + * 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 @@ -15,21 +15,46 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -*/ + */ package com.sk89q.worldedit; /** - * - * @author sk89q + * Parent for all WorldEdit exceptions. */ public abstract class WorldEditException extends Exception { - private static final long serialVersionUID = 3201997990797993987L; + /** + * Create a new exception. + */ protected WorldEditException() { } - protected WorldEditException(String msg) { - super(msg); + /** + * Create a new exception with a message. + * + * @param message the message + */ + protected WorldEditException(String message) { + super(message); + } + + /** + * Create a new exception with a message and a cause. + * + * @param message the message + * @param cause the cause + */ + protected WorldEditException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Create a new exception with a cause. + * + * @param cause the cause + */ + protected WorldEditException(Throwable cause) { + super(cause); } } diff --git a/src/main/java/com/sk89q/worldedit/blocks/BaseBlock.java b/src/main/java/com/sk89q/worldedit/blocks/BaseBlock.java index b65314fc9..f7f73321c 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/BaseBlock.java +++ b/src/main/java/com/sk89q/worldedit/blocks/BaseBlock.java @@ -19,36 +19,216 @@ package com.sk89q.worldedit.blocks; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.CuboidClipboard.FlipDirection; import com.sk89q.worldedit.foundation.Block; +import com.sk89q.worldedit.world.DataException; import java.util.Collection; /** - * Represents a block. - * - * @see Block new class to replace this one - * @author sk89q + * Represents a mutable copy of a block that is not tied to any 'real' block in a world. + * A single instance of this can be set to multiple locations and each location would + * have a copy of this instance's data. + *

+ * Implementations can and should extend this class to allow native implementations + * of NBT data handling, primarily for performance reasons. Subclasses can only convert + * from and to WorldEdit-native NBT structures when absolutely necessary (a.k.a. when + * {@link #getNbtData()} and {@link #setNbtData(CompoundTag)} are called). When + * overriding the NBT methods, {@link #getNbtId()} should be overridden too, otherwise + * the default implementation will invoke {@link #getNbtData()}, a potentially costly + * operation when it is not needed. Implementations may want to cache converted NBT data + * structures if possible. */ -public class BaseBlock extends Block { - +public class BaseBlock extends Block implements TileEntityBlock { + /** - * Construct the block with its type, with default data value 0. - * - * @param type type ID of block + * Indicates the highest possible block ID (inclusive) that can be used. This value + * is subject to change depending on the implementation, but internally this class + * only supports a range of 4096 IDs (for space reasons), which coincides with the + * number of possible IDs that official Minecraft supports as of version 1.3. */ - public BaseBlock(int type) { - this(type, 0); + public static final int MAX_ID = 4095; + + /** + * Indicates the maximum data value (inclusive) that can be used. Minecraft 1.4 may + * abolish usage of data values and this value may be removed in the future. + */ + public static final int MAX_DATA = 15; + + // Instances of this class should be _as small as possible_ because there will + // be millions of instances of this object. + + private short id; + private short data; + private CompoundTag nbtData; + + /** + * Construct a block with the given ID and a data value of 0. + * + * @param id ID value + * @see #setId(int) + */ + public BaseBlock(int id) { + internalSetId(id); + internalSetData(0); } /** - * Construct the block with its type and data. + * Construct a block with the given ID and data value. * - * @param type type ID of block + * @param id ID value * @param data data value + * @see #setId(int) + * @see #setData(int) */ - public BaseBlock(int type, int data) { - super(type, data); + public BaseBlock(int id, int data) { + internalSetId(id); + internalSetData(data); + } + + /** + * Construct a block with the given ID, data value, and NBT data structure. + * + * @param id ID value + * @param data data value + * @param nbtData NBT data + * @throws DataException if possibly the data is invalid + * @see #setId(int) + * @see #setData(int) + * @see #setNbtData(CompoundTag) + */ + public BaseBlock(int id, int data, CompoundTag nbtData) throws DataException { + setId(id); + setData(data); + setNbtData(nbtData); + } + + /** + * Get the ID of the block. + * + * @return ID (between 0 and {@link #MAX_ID}) + */ + public int getId() { + return id; + } + + /** + * Set the block ID. + * + * @param id block id (between 0 and {@link #MAX_ID}). + */ + protected final void internalSetId(int id) { + if (id > MAX_ID) { + throw new IllegalArgumentException("Can't have a block ID above " + + MAX_ID + " (" + id + " given)"); + } + + if (id < 0) { + throw new IllegalArgumentException("Can't have a block ID below 0"); + } + + this.id = (short) id; + } + + /** + * Set the block ID. + * + * @param id block id (between 0 and {@link #MAX_ID}). + */ + public void setId(int id) { + internalSetId(id); + } + + /** + * Get the block's data value. + * + * @return data value (0-15) + */ + public int getData() { + return data; + } + + /** + * Set the block's data value. + * + * @param data block data value (between 0 and {@link #MAX_DATA}). + */ + protected final void internalSetData(int data) { + if (data > MAX_DATA) { + throw new IllegalArgumentException( + "Can't have a block data value above " + MAX_DATA + " (" + + data + " given)"); + } + + if (data < -1) { + throw new IllegalArgumentException("Can't have a block data value below -1"); + } + + this.data = (short) data; + } + + /** + * Set the block's data value. + * + * @param data block data value (between 0 and {@link #MAX_DATA}). + */ + public void setData(int data) { + internalSetData(data); + } + + /** + * Set both the block's ID and data value. + * + * @param id ID value + * @param data data value + * @see #setId(int) + * @see #setData(int) + */ + public void setIdAndData(int id, int data) { + setId(id); + setData(data); + } + + /** + * Returns whether the data value is -1, indicating that this block is to be + * used as a wildcard matching block. + * + * @return true if the data value is -1 + */ + public boolean hasWildcardData() { + return getData() == -1; + } + + @Override + public boolean hasNbtData() { + return getNbtData() != null; + } + + @Override + public String getNbtId() { + CompoundTag nbtData = getNbtData(); + if (nbtData == null) { + return ""; + } + Tag idTag = nbtData.getValue().get("id"); + if (idTag != null && idTag instanceof StringTag) { + return ((StringTag) idTag).getValue(); + } else { + return ""; + } + } + + @Override + public CompoundTag getNbtData() { + return nbtData; + } + + @Override + public void setNbtData(CompoundTag nbtData) throws DataException { + this.nbtData = nbtData; } /** @@ -184,4 +364,17 @@ public class BaseBlock extends Block { } return false; } + + @Override + public int hashCode() { + int ret = getId() << 3; + if (getData() != (byte) -1) ret |= getData(); + return ret; + } + + @Override + public String toString() { + return "Block{ID:" + getId() + ", Data: " + getData() + "}"; + } + } diff --git a/src/main/java/com/sk89q/worldedit/blocks/BlockType.java b/src/main/java/com/sk89q/worldedit/blocks/BlockType.java index 5483f2ca6..10bc6c206 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/BlockType.java +++ b/src/main/java/com/sk89q/worldedit/blocks/BlockType.java @@ -19,16 +19,10 @@ package com.sk89q.worldedit.blocks; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Random; -import java.util.Set; - import com.sk89q.util.StringUtil; import com.sk89q.worldedit.PlayerDirection; -import com.sk89q.worldedit.foundation.Block; + +import java.util.*; /** * Block types. @@ -552,7 +546,7 @@ public enum BlockType { * @param block * @return */ - public static boolean canPassThrough(Block block) { + public static boolean canPassThrough(BaseBlock block) { return canPassThrough(block.getId(), block.getData()); } @@ -649,7 +643,7 @@ public enum BlockType { * @param block * @return */ - public static double centralTopLimit(Block block) { + public static double centralTopLimit(BaseBlock block) { return centralTopLimit(block.getId(), block.getData()); } @@ -1053,7 +1047,7 @@ public enum BlockType { * @param block The block * @return true if the block type is naturally occuring */ - public static boolean isNaturalTerrainBlock(Block block) { + public static boolean isNaturalTerrainBlock(BaseBlock block) { return isNaturalTerrainBlock(block.getId(), block.getData()); } diff --git a/src/main/java/com/sk89q/worldedit/blocks/ChestBlock.java b/src/main/java/com/sk89q/worldedit/blocks/ChestBlock.java index 1b66e4304..db161e1c8 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/ChestBlock.java +++ b/src/main/java/com/sk89q/worldedit/blocks/ChestBlock.java @@ -29,7 +29,7 @@ import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.NBTUtils; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.data.DataException; +import com.sk89q.worldedit.world.DataException; /** * Represents a chest block. diff --git a/src/main/java/com/sk89q/worldedit/blocks/ContainerBlock.java b/src/main/java/com/sk89q/worldedit/blocks/ContainerBlock.java index 60be36134..1796e66dd 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/ContainerBlock.java +++ b/src/main/java/com/sk89q/worldedit/blocks/ContainerBlock.java @@ -30,7 +30,7 @@ import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.NBTUtils; import com.sk89q.jnbt.ShortTag; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.data.DataException; +import com.sk89q.worldedit.world.DataException; /** * Represents a block that stores items. diff --git a/src/main/java/com/sk89q/worldedit/blocks/DispenserBlock.java b/src/main/java/com/sk89q/worldedit/blocks/DispenserBlock.java index 81c8e9c9b..169448656 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/DispenserBlock.java +++ b/src/main/java/com/sk89q/worldedit/blocks/DispenserBlock.java @@ -29,7 +29,7 @@ import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.NBTUtils; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.data.DataException; +import com.sk89q.worldedit.world.DataException; /** * Represents dispensers. diff --git a/src/main/java/com/sk89q/worldedit/blocks/FurnaceBlock.java b/src/main/java/com/sk89q/worldedit/blocks/FurnaceBlock.java index b0187a262..5fc017eb1 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/FurnaceBlock.java +++ b/src/main/java/com/sk89q/worldedit/blocks/FurnaceBlock.java @@ -30,7 +30,7 @@ import com.sk89q.jnbt.NBTUtils; import com.sk89q.jnbt.ShortTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.data.DataException; +import com.sk89q.worldedit.world.DataException; /** * Represents a furnace block. diff --git a/src/main/java/com/sk89q/worldedit/blocks/LazyBlock.java b/src/main/java/com/sk89q/worldedit/blocks/LazyBlock.java new file mode 100644 index 000000000..54325671f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/blocks/LazyBlock.java @@ -0,0 +1,105 @@ +/* + * 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.blocks; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.extent.Extent; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A implementation of a lazy block for {@link Extent#getLazyBlock(Vector)} + * that takes the block's ID and metadata, but will defer loading of NBT + * data until time of access. + *

+ * NBT data is later loaded using a call to {@link Extent#getBlock(Vector)} + * with a stored {@link Extent} and location. + *

+ * All mutators on this object will throw an + * {@link UnsupportedOperationException}. + */ +public class LazyBlock extends BaseBlock { + + private final Extent extent; + private final Vector position; + private boolean loaded = false; + + /** + * Create a new lazy block. + * + * @param type the block type + * @param extent the extent to later load the full block data from + * @param position the position to later load the full block data from + */ + public LazyBlock(int type, Extent extent, Vector position) { + super(type); + checkNotNull(extent); + checkNotNull(position); + this.extent = extent; + this.position = position; + } + + /** + * Create a new lazy block. + * + * @param type the block type + * @param data the data value + * @param extent the extent to later load the full block data from + * @param position the position to later load the full block data from + */ + public LazyBlock(int type, int data, Extent extent, Vector position) { + super(type, data); + checkNotNull(extent); + checkNotNull(position); + this.extent = extent; + this.position = position; + } + + @Override + public void setId(int id) { + throw new UnsupportedOperationException("This object is immutable"); + } + + @Override + public void setData(int data) { + throw new UnsupportedOperationException("This object is immutable"); + } + + @Override + public CompoundTag getNbtData() { + if (!loaded) { + BaseBlock loadedBlock = extent.getBlock(position); + try { + super.setNbtData(loadedBlock.getNbtData()); + } catch (DataException e) { + throw new RuntimeException(e); + } + } + return super.getNbtData(); + } + + @Override + public void setNbtData(CompoundTag nbtData) throws DataException { + throw new UnsupportedOperationException("This object is immutable"); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java b/src/main/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java index 746b1ba67..590c71d1b 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java +++ b/src/main/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java @@ -29,8 +29,8 @@ import com.sk89q.jnbt.ShortTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.MobType; -import com.sk89q.worldedit.data.DataException; -import com.sk89q.worldedit.data.InvalidFormatException; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.storage.InvalidFormatException; /** * A mob spawner block. diff --git a/src/main/java/com/sk89q/worldedit/blocks/NoteBlock.java b/src/main/java/com/sk89q/worldedit/blocks/NoteBlock.java index 283ca4c37..ca4be9a6e 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/NoteBlock.java +++ b/src/main/java/com/sk89q/worldedit/blocks/NoteBlock.java @@ -26,7 +26,7 @@ import com.sk89q.jnbt.ByteTag; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.data.DataException; +import com.sk89q.worldedit.world.DataException; /** * A note block. diff --git a/src/main/java/com/sk89q/worldedit/blocks/SignBlock.java b/src/main/java/com/sk89q/worldedit/blocks/SignBlock.java index f593b0d05..5b78fa417 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/SignBlock.java +++ b/src/main/java/com/sk89q/worldedit/blocks/SignBlock.java @@ -25,7 +25,7 @@ import java.util.Map; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.data.DataException; +import com.sk89q.worldedit.world.DataException; /** * Represents a sign block. diff --git a/src/main/java/com/sk89q/worldedit/blocks/SkullBlock.java b/src/main/java/com/sk89q/worldedit/blocks/SkullBlock.java index 66179b495..3bb2bc483 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/SkullBlock.java +++ b/src/main/java/com/sk89q/worldedit/blocks/SkullBlock.java @@ -26,7 +26,7 @@ import com.sk89q.jnbt.ByteTag; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.data.DataException; +import com.sk89q.worldedit.world.DataException; /** * A skull block. diff --git a/src/main/java/com/sk89q/worldedit/blocks/TileEntityBlock.java b/src/main/java/com/sk89q/worldedit/blocks/TileEntityBlock.java index 11d7fcc2f..d6e747eee 100644 --- a/src/main/java/com/sk89q/worldedit/blocks/TileEntityBlock.java +++ b/src/main/java/com/sk89q/worldedit/blocks/TileEntityBlock.java @@ -19,7 +19,7 @@ package com.sk89q.worldedit.blocks; -import com.sk89q.worldedit.foundation.NbtValued; +import com.sk89q.worldedit.world.NbtValued; /** * Indicates a block that contains extra data identified as an NBT structure. Compared diff --git a/src/main/java/com/sk89q/worldedit/commands/BiomeCommands.java b/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java similarity index 99% rename from src/main/java/com/sk89q/worldedit/commands/BiomeCommands.java rename to src/main/java/com/sk89q/worldedit/command/BiomeCommands.java index f25c25cd8..63fa1a12d 100644 --- a/src/main/java/com/sk89q/worldedit/commands/BiomeCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java @@ -1,4 +1,4 @@ -package com.sk89q.worldedit.commands; +package com.sk89q.worldedit.command; import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION; diff --git a/src/main/java/com/sk89q/worldedit/commands/BrushCommands.java b/src/main/java/com/sk89q/worldedit/command/BrushCommands.java similarity index 92% rename from src/main/java/com/sk89q/worldedit/commands/BrushCommands.java rename to src/main/java/com/sk89q/worldedit/command/BrushCommands.java index cffe67220..a8dbd6ce5 100644 --- a/src/main/java/com/sk89q/worldedit/commands/BrushCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/BrushCommands.java @@ -1,293 +1,293 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.commands; - -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.worldedit.CuboidClipboard; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.LocalConfiguration; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.LocalWorld.KillFlags; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.blocks.BlockID; -import com.sk89q.worldedit.commands.UtilityCommands.FlagContainer; -import com.sk89q.worldedit.masks.BlockMask; -import com.sk89q.worldedit.patterns.Pattern; -import com.sk89q.worldedit.patterns.SingleBlockPattern; -import com.sk89q.worldedit.tools.BrushTool; -import com.sk89q.worldedit.tools.brushes.ButcherBrush; -import com.sk89q.worldedit.tools.brushes.ClipboardBrush; -import com.sk89q.worldedit.tools.brushes.CylinderBrush; -import com.sk89q.worldedit.tools.brushes.GravityBrush; -import com.sk89q.worldedit.tools.brushes.HollowCylinderBrush; -import com.sk89q.worldedit.tools.brushes.HollowSphereBrush; -import com.sk89q.worldedit.tools.brushes.SmoothBrush; -import com.sk89q.worldedit.tools.brushes.SphereBrush; - -/** - * Brush shape commands. - * - * @author sk89q - */ -public class BrushCommands { - private final WorldEdit we; - - public BrushCommands(WorldEdit we) { - this.we = we; - } - - @Command( - aliases = { "sphere", "s" }, - usage = " [radius]", - flags = "h", - desc = "Choose the sphere brush", - help = - "Chooses the sphere brush.\n" + - "The -h flag creates hollow spheres instead.", - min = 1, - max = 2 - ) - @CommandPermissions("worldedit.brush.sphere") - public void sphereBrush(CommandContext args, LocalSession session, - LocalPlayer player, EditSession editSession) throws WorldEditException { - - double radius = args.argsLength() > 1 ? args.getDouble(1) : 2; - we.checkMaxBrushRadius(radius); - - BrushTool tool = session.getBrushTool(player.getItemInHand()); - Pattern fill = we.getBlockPattern(player, args.getString(0)); - tool.setFill(fill); - tool.setSize(radius); - - if (args.hasFlag('h')) { - tool.setBrush(new HollowSphereBrush(), "worldedit.brush.sphere"); - } else { - tool.setBrush(new SphereBrush(), "worldedit.brush.sphere"); - } - - player.print(String.format("Sphere brush shape equipped (%.0f).", - radius)); - } - - @Command( - aliases = { "cylinder", "cyl", "c" }, - usage = " [radius] [height]", - flags = "h", - desc = "Choose the cylinder brush", - help = - "Chooses the cylinder brush.\n" + - "The -h flag creates hollow cylinders instead.", - min = 1, - max = 3 - ) - @CommandPermissions("worldedit.brush.cylinder") - public void cylinderBrush(CommandContext args, LocalSession session, - LocalPlayer player, EditSession editSession) throws WorldEditException { - - double radius = args.argsLength() > 1 ? args.getDouble(1) : 2; - we.checkMaxBrushRadius(radius); - - int height = args.argsLength() > 2 ? args.getInteger(2) : 1; - we.checkMaxBrushRadius(height); - - BrushTool tool = session.getBrushTool(player.getItemInHand()); - Pattern fill = we.getBlockPattern(player, args.getString(0)); - tool.setFill(fill); - tool.setSize(radius); - - if (args.hasFlag('h')) { - tool.setBrush(new HollowCylinderBrush(height), "worldedit.brush.cylinder"); - } else { - tool.setBrush(new CylinderBrush(height), "worldedit.brush.cylinder"); - } - - player.print(String.format("Cylinder brush shape equipped (%.0f by %d).", - radius, height)); - } - - @Command( - aliases = { "clipboard", "copy" }, - usage = "", - flags = "a", - desc = "Choose the clipboard brush", - help = - "Chooses the clipboard brush.\n" + - "The -a flag makes it not paste air.", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.brush.clipboard") - public void clipboardBrush(CommandContext args, LocalSession session, - LocalPlayer player, EditSession editSession) throws WorldEditException { - - CuboidClipboard clipboard = session.getClipboard(); - - if (clipboard == null) { - player.printError("Copy something first."); - return; - } - - Vector size = clipboard.getSize(); - - we.checkMaxBrushRadius(size.getBlockX()); - we.checkMaxBrushRadius(size.getBlockY()); - we.checkMaxBrushRadius(size.getBlockZ()); - - BrushTool tool = session.getBrushTool(player.getItemInHand()); - tool.setBrush(new ClipboardBrush(clipboard, args.hasFlag('a')), "worldedit.brush.clipboard"); - - player.print("Clipboard brush shape equipped."); - } - - @Command( - aliases = { "smooth" }, - usage = "[size] [iterations]", - flags = "n", - desc = "Choose the terrain softener brush", - help = - "Chooses the terrain softener brush.\n" + - "The -n flag makes it only consider naturally occuring blocks.", - min = 0, - max = 2 - ) - @CommandPermissions("worldedit.brush.smooth") - public void smoothBrush(CommandContext args, LocalSession session, - LocalPlayer player, EditSession editSession) throws WorldEditException { - - double radius = args.argsLength() > 0 ? args.getDouble(0) : 2; - we.checkMaxBrushRadius(radius); - - int iterations = args.argsLength() > 1 ? args.getInteger(1) : 4; - - BrushTool tool = session.getBrushTool(player.getItemInHand()); - tool.setSize(radius); - tool.setBrush(new SmoothBrush(iterations, args.hasFlag('n')), "worldedit.brush.smooth"); - - player.print(String.format("Smooth brush equipped (%.0f x %dx, using " + (args.hasFlag('n') ? "natural blocks only" : "any block") + ").", - radius, iterations)); - } - - @Command( - aliases = { "ex", "extinguish" }, - usage = "[radius]", - desc = "Shortcut fire extinguisher brush", - min = 0, - max = 1 - ) - @CommandPermissions("worldedit.brush.ex") - public void extinguishBrush(CommandContext args, LocalSession session, - LocalPlayer player, EditSession editSession) throws WorldEditException { - - double radius = args.argsLength() > 1 ? args.getDouble(1) : 5; - we.checkMaxBrushRadius(radius); - - BrushTool tool = session.getBrushTool(player.getItemInHand()); - Pattern fill = new SingleBlockPattern(new BaseBlock(0)); - tool.setFill(fill); - tool.setSize(radius); - tool.setMask(new BlockMask(new BaseBlock(BlockID.FIRE))); - tool.setBrush(new SphereBrush(), "worldedit.brush.ex"); - - player.print(String.format("Extinguisher equipped (%.0f).", - radius)); - } - - @Command( - aliases = { "gravity", "grav" }, - usage = "[radius]", - flags = "h", - desc = "Gravity brush", - help = - "This brush simulates the affect of gravity.\n" + - "The -h flag makes it affect blocks starting at the world's max y, " + - "instead of the clicked block's y + radius.", - min = 0, - max = 1 - ) - @CommandPermissions("worldedit.brush.gravity") - public void gravityBrush(CommandContext args, LocalSession session, - LocalPlayer player, EditSession editSession) throws WorldEditException { - - double radius = args.argsLength() > 0 ? args.getDouble(0) : 5; - we.checkMaxBrushRadius(radius); - - BrushTool tool = session.getBrushTool(player.getItemInHand()); - tool.setSize(radius); - tool.setBrush(new GravityBrush(args.hasFlag('h')), "worldedit.brush.gravity"); - - player.print(String.format("Gravity brush equipped (%.0f).", - radius)); - } - - @Command( - aliases = { "butcher", "kill" }, - usage = "[radius] [command flags]", - desc = "Butcher brush", - help = "Kills nearby mobs within the specified radius.\n" + - "Any number of 'flags' that the //butcher command uses\n" + - "may be specified as an argument", - min = 0, - max = 2 - ) - @CommandPermissions("worldedit.brush.butcher") - public void butcherBrush(CommandContext args, LocalSession session, - LocalPlayer player, EditSession editSession) throws WorldEditException { - - LocalConfiguration config = we.getConfiguration(); - - double radius = args.argsLength() > 0 ? args.getDouble(0) : 5; - double maxRadius = config.maxBrushRadius; - // hmmmm not horribly worried about this because -1 is still rather efficient, - // the problem arises when butcherMaxRadius is some really high number but not infinite - // - original idea taken from https://github.com/sk89q/worldedit/pull/198#issuecomment-6463108 - if (player.hasPermission("worldedit.butcher")) { - maxRadius = Math.max(config.maxBrushRadius, config.butcherMaxRadius); - } - if (radius > maxRadius) { - player.printError("Maximum allowed brush radius: " + maxRadius); - return; - } - - FlagContainer flags = new FlagContainer(player); - if (args.argsLength() == 2) { - String flagString = args.getString(1); - // straight from the command, using contains instead of hasflag - flags.or(KillFlags.FRIENDLY , flagString.contains("f")); // No permission check here. Flags will instead be filtered by the subsequent calls. - flags.or(KillFlags.PETS , flagString.contains("p"), "worldedit.butcher.pets"); - flags.or(KillFlags.NPCS , flagString.contains("n"), "worldedit.butcher.npcs"); - flags.or(KillFlags.GOLEMS , flagString.contains("g"), "worldedit.butcher.golems"); - flags.or(KillFlags.ANIMALS , flagString.contains("a"), "worldedit.butcher.animals"); - flags.or(KillFlags.AMBIENT , flagString.contains("b"), "worldedit.butcher.ambient"); - flags.or(KillFlags.WITH_LIGHTNING, flagString.contains("l"), "worldedit.butcher.lightning"); - } - BrushTool tool = session.getBrushTool(player.getItemInHand()); - tool.setSize(radius); - tool.setBrush(new ButcherBrush(flags.flags), "worldedit.brush.butcher"); - - player.print(String.format("Butcher brush equipped (%.0f).", - radius)); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.command; + +import com.sk89q.minecraft.util.commands.Command; +import com.sk89q.minecraft.util.commands.CommandContext; +import com.sk89q.minecraft.util.commands.CommandPermissions; +import com.sk89q.worldedit.CuboidClipboard; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.LocalWorld.KillFlags; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockID; +import com.sk89q.worldedit.command.UtilityCommands.FlagContainer; +import com.sk89q.worldedit.masks.BlockMask; +import com.sk89q.worldedit.patterns.Pattern; +import com.sk89q.worldedit.patterns.SingleBlockPattern; +import com.sk89q.worldedit.command.tool.BrushTool; +import com.sk89q.worldedit.command.tool.brush.ButcherBrush; +import com.sk89q.worldedit.command.tool.brush.ClipboardBrush; +import com.sk89q.worldedit.command.tool.brush.CylinderBrush; +import com.sk89q.worldedit.command.tool.brush.GravityBrush; +import com.sk89q.worldedit.command.tool.brush.HollowCylinderBrush; +import com.sk89q.worldedit.command.tool.brush.HollowSphereBrush; +import com.sk89q.worldedit.command.tool.brush.SmoothBrush; +import com.sk89q.worldedit.command.tool.brush.SphereBrush; + +/** + * Brush shape commands. + * + * @author sk89q + */ +public class BrushCommands { + private final WorldEdit we; + + public BrushCommands(WorldEdit we) { + this.we = we; + } + + @Command( + aliases = { "sphere", "s" }, + usage = " [radius]", + flags = "h", + desc = "Choose the sphere brush", + help = + "Chooses the sphere brush.\n" + + "The -h flag creates hollow spheres instead.", + min = 1, + max = 2 + ) + @CommandPermissions("worldedit.brush.sphere") + public void sphereBrush(CommandContext args, LocalSession session, + LocalPlayer player, EditSession editSession) throws WorldEditException { + + double radius = args.argsLength() > 1 ? args.getDouble(1) : 2; + we.checkMaxBrushRadius(radius); + + BrushTool tool = session.getBrushTool(player.getItemInHand()); + Pattern fill = we.getBlockPattern(player, args.getString(0)); + tool.setFill(fill); + tool.setSize(radius); + + if (args.hasFlag('h')) { + tool.setBrush(new HollowSphereBrush(), "worldedit.brush.sphere"); + } else { + tool.setBrush(new SphereBrush(), "worldedit.brush.sphere"); + } + + player.print(String.format("Sphere brush shape equipped (%.0f).", + radius)); + } + + @Command( + aliases = { "cylinder", "cyl", "c" }, + usage = " [radius] [height]", + flags = "h", + desc = "Choose the cylinder brush", + help = + "Chooses the cylinder brush.\n" + + "The -h flag creates hollow cylinders instead.", + min = 1, + max = 3 + ) + @CommandPermissions("worldedit.brush.cylinder") + public void cylinderBrush(CommandContext args, LocalSession session, + LocalPlayer player, EditSession editSession) throws WorldEditException { + + double radius = args.argsLength() > 1 ? args.getDouble(1) : 2; + we.checkMaxBrushRadius(radius); + + int height = args.argsLength() > 2 ? args.getInteger(2) : 1; + we.checkMaxBrushRadius(height); + + BrushTool tool = session.getBrushTool(player.getItemInHand()); + Pattern fill = we.getBlockPattern(player, args.getString(0)); + tool.setFill(fill); + tool.setSize(radius); + + if (args.hasFlag('h')) { + tool.setBrush(new HollowCylinderBrush(height), "worldedit.brush.cylinder"); + } else { + tool.setBrush(new CylinderBrush(height), "worldedit.brush.cylinder"); + } + + player.print(String.format("Cylinder brush shape equipped (%.0f by %d).", + radius, height)); + } + + @Command( + aliases = { "clipboard", "copy" }, + usage = "", + flags = "a", + desc = "Choose the clipboard brush", + help = + "Chooses the clipboard brush.\n" + + "The -a flag makes it not paste air.", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.brush.clipboard") + public void clipboardBrush(CommandContext args, LocalSession session, + LocalPlayer player, EditSession editSession) throws WorldEditException { + + CuboidClipboard clipboard = session.getClipboard(); + + if (clipboard == null) { + player.printError("Copy something first."); + return; + } + + Vector size = clipboard.getSize(); + + we.checkMaxBrushRadius(size.getBlockX()); + we.checkMaxBrushRadius(size.getBlockY()); + we.checkMaxBrushRadius(size.getBlockZ()); + + BrushTool tool = session.getBrushTool(player.getItemInHand()); + tool.setBrush(new ClipboardBrush(clipboard, args.hasFlag('a')), "worldedit.brush.clipboard"); + + player.print("Clipboard brush shape equipped."); + } + + @Command( + aliases = { "smooth" }, + usage = "[size] [iterations]", + flags = "n", + desc = "Choose the terrain softener brush", + help = + "Chooses the terrain softener brush.\n" + + "The -n flag makes it only consider naturally occuring blocks.", + min = 0, + max = 2 + ) + @CommandPermissions("worldedit.brush.smooth") + public void smoothBrush(CommandContext args, LocalSession session, + LocalPlayer player, EditSession editSession) throws WorldEditException { + + double radius = args.argsLength() > 0 ? args.getDouble(0) : 2; + we.checkMaxBrushRadius(radius); + + int iterations = args.argsLength() > 1 ? args.getInteger(1) : 4; + + BrushTool tool = session.getBrushTool(player.getItemInHand()); + tool.setSize(radius); + tool.setBrush(new SmoothBrush(iterations, args.hasFlag('n')), "worldedit.brush.smooth"); + + player.print(String.format("Smooth brush equipped (%.0f x %dx, using " + (args.hasFlag('n') ? "natural blocks only" : "any block") + ").", + radius, iterations)); + } + + @Command( + aliases = { "ex", "extinguish" }, + usage = "[radius]", + desc = "Shortcut fire extinguisher brush", + min = 0, + max = 1 + ) + @CommandPermissions("worldedit.brush.ex") + public void extinguishBrush(CommandContext args, LocalSession session, + LocalPlayer player, EditSession editSession) throws WorldEditException { + + double radius = args.argsLength() > 1 ? args.getDouble(1) : 5; + we.checkMaxBrushRadius(radius); + + BrushTool tool = session.getBrushTool(player.getItemInHand()); + Pattern fill = new SingleBlockPattern(new BaseBlock(0)); + tool.setFill(fill); + tool.setSize(radius); + tool.setMask(new BlockMask(new BaseBlock(BlockID.FIRE))); + tool.setBrush(new SphereBrush(), "worldedit.brush.ex"); + + player.print(String.format("Extinguisher equipped (%.0f).", + radius)); + } + + @Command( + aliases = { "gravity", "grav" }, + usage = "[radius]", + flags = "h", + desc = "Gravity brush", + help = + "This brush simulates the affect of gravity.\n" + + "The -h flag makes it affect blocks starting at the world's max y, " + + "instead of the clicked block's y + radius.", + min = 0, + max = 1 + ) + @CommandPermissions("worldedit.brush.gravity") + public void gravityBrush(CommandContext args, LocalSession session, + LocalPlayer player, EditSession editSession) throws WorldEditException { + + double radius = args.argsLength() > 0 ? args.getDouble(0) : 5; + we.checkMaxBrushRadius(radius); + + BrushTool tool = session.getBrushTool(player.getItemInHand()); + tool.setSize(radius); + tool.setBrush(new GravityBrush(args.hasFlag('h')), "worldedit.brush.gravity"); + + player.print(String.format("Gravity brush equipped (%.0f).", + radius)); + } + + @Command( + aliases = { "butcher", "kill" }, + usage = "[radius] [command flags]", + desc = "Butcher brush", + help = "Kills nearby mobs within the specified radius.\n" + + "Any number of 'flags' that the //butcher command uses\n" + + "may be specified as an argument", + min = 0, + max = 2 + ) + @CommandPermissions("worldedit.brush.butcher") + public void butcherBrush(CommandContext args, LocalSession session, + LocalPlayer player, EditSession editSession) throws WorldEditException { + + LocalConfiguration config = we.getConfiguration(); + + double radius = args.argsLength() > 0 ? args.getDouble(0) : 5; + double maxRadius = config.maxBrushRadius; + // hmmmm not horribly worried about this because -1 is still rather efficient, + // the problem arises when butcherMaxRadius is some really high number but not infinite + // - original idea taken from https://github.com/sk89q/worldedit/pull/198#issuecomment-6463108 + if (player.hasPermission("worldedit.butcher")) { + maxRadius = Math.max(config.maxBrushRadius, config.butcherMaxRadius); + } + if (radius > maxRadius) { + player.printError("Maximum allowed brush radius: " + maxRadius); + return; + } + + FlagContainer flags = new FlagContainer(player); + if (args.argsLength() == 2) { + String flagString = args.getString(1); + // straight from the command, using contains instead of hasflag + flags.or(KillFlags.FRIENDLY , flagString.contains("f")); // No permission check here. Flags will instead be filtered by the subsequent calls. + flags.or(KillFlags.PETS , flagString.contains("p"), "worldedit.butcher.pets"); + flags.or(KillFlags.NPCS , flagString.contains("n"), "worldedit.butcher.npcs"); + flags.or(KillFlags.GOLEMS , flagString.contains("g"), "worldedit.butcher.golems"); + flags.or(KillFlags.ANIMALS , flagString.contains("a"), "worldedit.butcher.animals"); + flags.or(KillFlags.AMBIENT , flagString.contains("b"), "worldedit.butcher.ambient"); + flags.or(KillFlags.WITH_LIGHTNING, flagString.contains("l"), "worldedit.butcher.lightning"); + } + BrushTool tool = session.getBrushTool(player.getItemInHand()); + tool.setSize(radius); + tool.setBrush(new ButcherBrush(flags.flags), "worldedit.brush.butcher"); + + player.print(String.format("Butcher brush equipped (%.0f).", + radius)); + } +} diff --git a/src/main/java/com/sk89q/worldedit/commands/ChunkCommands.java b/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/commands/ChunkCommands.java rename to src/main/java/com/sk89q/worldedit/command/ChunkCommands.java index 887404ef6..583174e06 100644 --- a/src/main/java/com/sk89q/worldedit/commands/ChunkCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java @@ -1,179 +1,179 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.commands; - -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.util.Set; -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.Logging; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.*; -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.data.LegacyChunkStore; -import com.sk89q.worldedit.data.McRegionChunkStore; - -/** - * Chunk tools. - * - * @author sk89q - */ -public class ChunkCommands { - private final WorldEdit we; - - public ChunkCommands(WorldEdit we) { - this.we = we; - } - - @Command( - aliases = { "chunkinfo" }, - usage = "", - desc = "Get information about the chunk that you are inside", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.chunkinfo") - public void chunkInfo(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - Vector pos = player.getBlockIn(); - int chunkX = (int) Math.floor(pos.getBlockX() / 16.0); - int chunkZ = (int) Math.floor(pos.getBlockZ() / 16.0); - - String folder1 = Integer.toString(WorldEdit.divisorMod(chunkX, 64), 36); - String folder2 = Integer.toString(WorldEdit.divisorMod(chunkZ, 64), 36); - String filename = "c." + Integer.toString(chunkX, 36) - + "." + Integer.toString(chunkZ, 36) + ".dat"; - - player.print("Chunk: " + chunkX + ", " + chunkZ); - player.print("Old format: " + folder1 + "/" + folder2 + "/" + filename); - player.print("McRegion: region/" + McRegionChunkStore.getFilename( - new Vector2D(chunkX, chunkZ))); - } - - @Command( - aliases = { "listchunks" }, - usage = "", - desc = "List chunks that your selection includes", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.listchunks") - public void listChunks(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - Set chunks = session.getSelection(player.getWorld()).getChunks(); - - for (Vector2D chunk : chunks) { - player.print(LegacyChunkStore.getFilename(chunk)); - } - } - - @Command( - aliases = { "delchunks" }, - usage = "", - desc = "Delete chunks that your selection includes", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.delchunks") - @Logging(REGION) - public void deleteChunks(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - player.print("Note that this command does not yet support the mcregion format."); - LocalConfiguration config = we.getConfiguration(); - - Set chunks = session.getSelection(player.getWorld()).getChunks(); - FileOutputStream out = null; - - if (config.shellSaveType == null) { - player.printError("Shell script type must be configured: 'bat' or 'bash' expected."); - } else if (config.shellSaveType.equalsIgnoreCase("bat")) { - try { - out = new FileOutputStream("worldedit-delchunks.bat"); - OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8"); - writer.write("@ECHO off\r\n"); - writer.write("ECHO This batch file was generated by WorldEdit.\r\n"); - writer.write("ECHO It contains a list of chunks that were in the selected region\r\n"); - writer.write("ECHO at the time that the /delchunks command was used. Run this file\r\n"); - writer.write("ECHO in order to delete the chunk files listed in this file.\r\n"); - writer.write("ECHO.\r\n"); - writer.write("PAUSE\r\n"); - - for (Vector2D chunk : chunks) { - String filename = LegacyChunkStore.getFilename(chunk); - writer.write("ECHO " + filename + "\r\n"); - writer.write("DEL \"world/" + filename + "\"\r\n"); - } - - writer.write("ECHO Complete.\r\n"); - writer.write("PAUSE\r\n"); - writer.close(); - player.print("worldedit-delchunks.bat written. Run it when no one is near the region."); - } catch (IOException e) { - player.printError("Error occurred: " + e.getMessage()); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException ie) { } - } - } - } else if (config.shellSaveType.equalsIgnoreCase("bash")) { - try { - out = new FileOutputStream("worldedit-delchunks.sh"); - OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8"); - writer.write("#!/bin/bash\n"); - writer.write("echo This shell file was generated by WorldEdit.\n"); - writer.write("echo It contains a list of chunks that were in the selected region\n"); - writer.write("echo at the time that the /delchunks command was used. Run this file\n"); - writer.write("echo in order to delete the chunk files listed in this file.\n"); - writer.write("echo\n"); - writer.write("read -p \"Press any key to continue...\"\n"); - - for (Vector2D chunk : chunks) { - String filename = LegacyChunkStore.getFilename(chunk); - writer.write("echo " + filename + "\n"); - writer.write("rm \"world/" + filename + "\"\n"); - } - - writer.write("echo Complete.\n"); - writer.write("read -p \"Press any key to continue...\"\n"); - writer.close(); - player.print("worldedit-delchunks.sh written. Run it when no one is near the region."); - player.print("You will have to chmod it to be executable."); - } catch (IOException e) { - player.printError("Error occurred: " + e.getMessage()); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException ie) { - } - } - } - } else { - player.printError("Shell script type must be configured: 'bat' or 'bash' expected."); - } - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.util.Set; +import com.sk89q.minecraft.util.commands.Command; +import com.sk89q.minecraft.util.commands.CommandContext; +import com.sk89q.minecraft.util.commands.CommandPermissions; +import com.sk89q.minecraft.util.commands.Logging; +import static com.sk89q.minecraft.util.commands.Logging.LogMode.*; +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.world.storage.LegacyChunkStore; +import com.sk89q.worldedit.world.storage.McRegionChunkStore; + +/** + * Chunk tools. + * + * @author sk89q + */ +public class ChunkCommands { + private final WorldEdit we; + + public ChunkCommands(WorldEdit we) { + this.we = we; + } + + @Command( + aliases = { "chunkinfo" }, + usage = "", + desc = "Get information about the chunk that you are inside", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.chunkinfo") + public void chunkInfo(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + Vector pos = player.getBlockIn(); + int chunkX = (int) Math.floor(pos.getBlockX() / 16.0); + int chunkZ = (int) Math.floor(pos.getBlockZ() / 16.0); + + String folder1 = Integer.toString(WorldEdit.divisorMod(chunkX, 64), 36); + String folder2 = Integer.toString(WorldEdit.divisorMod(chunkZ, 64), 36); + String filename = "c." + Integer.toString(chunkX, 36) + + "." + Integer.toString(chunkZ, 36) + ".dat"; + + player.print("Chunk: " + chunkX + ", " + chunkZ); + player.print("Old format: " + folder1 + "/" + folder2 + "/" + filename); + player.print("McRegion: region/" + McRegionChunkStore.getFilename( + new Vector2D(chunkX, chunkZ))); + } + + @Command( + aliases = { "listchunks" }, + usage = "", + desc = "List chunks that your selection includes", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.listchunks") + public void listChunks(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + Set chunks = session.getSelection(player.getWorld()).getChunks(); + + for (Vector2D chunk : chunks) { + player.print(LegacyChunkStore.getFilename(chunk)); + } + } + + @Command( + aliases = { "delchunks" }, + usage = "", + desc = "Delete chunks that your selection includes", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.delchunks") + @Logging(REGION) + public void deleteChunks(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + player.print("Note that this command does not yet support the mcregion format."); + LocalConfiguration config = we.getConfiguration(); + + Set chunks = session.getSelection(player.getWorld()).getChunks(); + FileOutputStream out = null; + + if (config.shellSaveType == null) { + player.printError("Shell script type must be configured: 'bat' or 'bash' expected."); + } else if (config.shellSaveType.equalsIgnoreCase("bat")) { + try { + out = new FileOutputStream("worldedit-delchunks.bat"); + OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8"); + writer.write("@ECHO off\r\n"); + writer.write("ECHO This batch file was generated by WorldEdit.\r\n"); + writer.write("ECHO It contains a list of chunks that were in the selected region\r\n"); + writer.write("ECHO at the time that the /delchunks command was used. Run this file\r\n"); + writer.write("ECHO in order to delete the chunk files listed in this file.\r\n"); + writer.write("ECHO.\r\n"); + writer.write("PAUSE\r\n"); + + for (Vector2D chunk : chunks) { + String filename = LegacyChunkStore.getFilename(chunk); + writer.write("ECHO " + filename + "\r\n"); + writer.write("DEL \"world/" + filename + "\"\r\n"); + } + + writer.write("ECHO Complete.\r\n"); + writer.write("PAUSE\r\n"); + writer.close(); + player.print("worldedit-delchunks.bat written. Run it when no one is near the region."); + } catch (IOException e) { + player.printError("Error occurred: " + e.getMessage()); + } finally { + if (out != null) { + try { + out.close(); + } catch (IOException ie) { } + } + } + } else if (config.shellSaveType.equalsIgnoreCase("bash")) { + try { + out = new FileOutputStream("worldedit-delchunks.sh"); + OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8"); + writer.write("#!/bin/bash\n"); + writer.write("echo This shell file was generated by WorldEdit.\n"); + writer.write("echo It contains a list of chunks that were in the selected region\n"); + writer.write("echo at the time that the /delchunks command was used. Run this file\n"); + writer.write("echo in order to delete the chunk files listed in this file.\n"); + writer.write("echo\n"); + writer.write("read -p \"Press any key to continue...\"\n"); + + for (Vector2D chunk : chunks) { + String filename = LegacyChunkStore.getFilename(chunk); + writer.write("echo " + filename + "\n"); + writer.write("rm \"world/" + filename + "\"\n"); + } + + writer.write("echo Complete.\n"); + writer.write("read -p \"Press any key to continue...\"\n"); + writer.close(); + player.print("worldedit-delchunks.sh written. Run it when no one is near the region."); + player.print("You will have to chmod it to be executable."); + } catch (IOException e) { + player.printError("Error occurred: " + e.getMessage()); + } finally { + if (out != null) { + try { + out.close(); + } catch (IOException ie) { + } + } + } + } else { + player.printError("Shell script type must be configured: 'bat' or 'bash' expected."); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/commands/ClipboardCommands.java b/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/commands/ClipboardCommands.java rename to src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java index a38530f3f..f7a8fd61c 100644 --- a/src/main/java/com/sk89q/worldedit/commands/ClipboardCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -1,286 +1,286 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.commands; - -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.Logging; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.*; - -import com.sk89q.minecraft.util.commands.NestedCommand; -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.blocks.BlockID; -import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.regions.CuboidRegionSelector; -import com.sk89q.worldedit.regions.Region; - -/** - * Clipboard commands. - * - * @author sk89q - */ -public class ClipboardCommands { - private final WorldEdit we; - - public ClipboardCommands(WorldEdit we) { - this.we = we; - } - - @Command( - aliases = { "/copy" }, - flags = "e", - desc = "Copy the selection to the clipboard", - help = "Copy the selection to the clipboard\n" + - "Flags:\n" + - " -e controls whether entities are copied\n" + - "WARNING: Pasting entities cannot yet be undone!", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.clipboard.copy") - public void copy(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - Region region = session.getSelection(player.getWorld()); - Vector min = region.getMinimumPoint(); - Vector max = region.getMaximumPoint(); - Vector pos = session.getPlacementPosition(player); - - CuboidClipboard clipboard = new CuboidClipboard( - max.subtract(min).add(Vector.ONE), - min, min.subtract(pos)); - - if (region instanceof CuboidRegion) { - clipboard.copy(editSession); - } else { - clipboard.copy(editSession, region); - } - - if (args.hasFlag('e')) { - for (LocalEntity entity : player.getWorld().getEntities(region)) { - clipboard.storeEntity(entity); - } - } - session.setClipboard(clipboard); - - player.print("Block(s) copied."); - } - - @Command( - aliases = { "/cut" }, - usage = "[leave-id]", - desc = "Cut the selection to the clipboard", - help = "Copy the selection to the clipboard\n" + - "Flags:\n" + - " -e controls whether entities are copied\n" + - "WARNING: Cutting and pasting entities cannot yet be undone!", - flags = "e", - min = 0, - max = 1 - ) - @CommandPermissions("worldedit.clipboard.cut") - @Logging(REGION) - public void cut(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - BaseBlock block = new BaseBlock(BlockID.AIR); - LocalWorld world = player.getWorld(); - - if (args.argsLength() > 0) { - block = we.getBlock(player, args.getString(0)); - } - - Region region = session.getSelection(world); - Vector min = region.getMinimumPoint(); - Vector max = region.getMaximumPoint(); - Vector pos = session.getPlacementPosition(player); - - CuboidClipboard clipboard = new CuboidClipboard( - max.subtract(min).add(Vector.ONE), - min, min.subtract(pos)); - - if (region instanceof CuboidRegion) { - clipboard.copy(editSession); - } else { - clipboard.copy(editSession, region); - } - - if (args.hasFlag('e')) { - LocalEntity[] entities = world.getEntities(region); - for (LocalEntity entity : entities) { - clipboard.storeEntity(entity); - } - world.killEntities(entities); - } - session.setClipboard(clipboard); - - editSession.setBlocks(region, block); - player.print("Block(s) cut."); - } - - @Command( - aliases = { "/paste" }, - usage = "", - flags = "sao", - desc = "Paste the clipboard's contents", - help = - "Pastes the clipboard's contents.\n" + - "Flags:\n" + - " -a skips air blocks\n" + - " -o pastes at the original position\n" + - " -s selects the region after pasting", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.clipboard.paste") - @Logging(PLACEMENT) - public void paste(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - boolean atOrigin = args.hasFlag('o'); - boolean pasteNoAir = args.hasFlag('a'); - - CuboidClipboard clipboard = session.getClipboard(); - - Vector pos = atOrigin ? session.getClipboard().getOrigin() - : session.getPlacementPosition(player); - - if (atOrigin) { - clipboard.place(editSession, pos, pasteNoAir); - clipboard.pasteEntities(pos); - player.findFreePosition(); - player.print("Pasted to copy origin. Undo with //undo"); - } else { - clipboard.paste(editSession, pos, pasteNoAir, true); - player.findFreePosition(); - player.print("Pasted relative to you. Undo with //undo"); - } - - if (args.hasFlag('s')) { - LocalWorld world = player.getWorld(); - Vector pos2 = pos.add(clipboard.getSize().subtract(1, 1, 1)); - if (!atOrigin) { - pos2 = pos2.add(clipboard.getOffset()); - pos = pos.add(clipboard.getOffset()); - } - session.setRegionSelector(world, new CuboidRegionSelector(world, pos, pos2)); - session.getRegionSelector(world).learnChanges(); - session.getRegionSelector(world).explainRegionAdjust(player, session); - } - } - - @Command( - aliases = { "/rotate" }, - usage = "", - desc = "Rotate the contents of the clipboard", - min = 1, - max = 1 - ) - @CommandPermissions("worldedit.clipboard.rotate") - public void rotate(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - int angle = args.getInteger(0); - - if (angle % 90 == 0) { - CuboidClipboard clipboard = session.getClipboard(); - clipboard.rotate2D(angle); - player.print("Clipboard rotated by " + angle + " degrees."); - } else { - player.printError("Angles must be divisible by 90 degrees."); - } - } - - @Command( - aliases = { "/flip" }, - usage = "[dir]", - flags = "p", - desc = "Flip the contents of the clipboard.", - help = - "Flips the contents of the clipboard.\n" + - "The -p flag flips the selection around the player,\n" + - "instead of the selections center.", - min = 0, - max = 1 - ) - @CommandPermissions("worldedit.clipboard.flip") - public void flip(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - CuboidClipboard.FlipDirection dir = we.getFlipDirection(player, - args.argsLength() > 0 ? args.getString(0).toLowerCase() : "me"); - - CuboidClipboard clipboard = session.getClipboard(); - clipboard.flip(dir, args.hasFlag('p')); - player.print("Clipboard flipped."); - } - - @Command( - aliases = { "/load" }, - usage = "", - desc = "Load a schematic into your clipboard", - min = 0, - max = 1 - ) - @Deprecated - @CommandPermissions("worldedit.clipboard.load") - public void load(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - player.printError("This command is no longer used. See //schematic load."); - } - - @Command( - aliases = { "/save" }, - usage = "", - desc = "Save a schematic into your clipboard", - min = 0, - max = 1 - ) - @Deprecated - @CommandPermissions("worldedit.clipboard.save") - public void save(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - player.printError("This command is no longer used. See //schematic save."); - } - - @Command( - aliases = { "/schematic", "/schem"}, - desc = "Schematic-related commands" - ) - @NestedCommand(SchematicCommands.class) - public void schematic() {} - - @Command( - aliases = { "clearclipboard" }, - usage = "", - desc = "Clear your clipboard", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.clipboard.clear") - public void clearClipboard(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - session.setClipboard(null); - player.print("Clipboard cleared."); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command; + +import com.sk89q.minecraft.util.commands.Command; +import com.sk89q.minecraft.util.commands.CommandContext; +import com.sk89q.minecraft.util.commands.CommandPermissions; +import com.sk89q.minecraft.util.commands.Logging; +import static com.sk89q.minecraft.util.commands.Logging.LogMode.*; + +import com.sk89q.minecraft.util.commands.NestedCommand; +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockID; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; +import com.sk89q.worldedit.regions.Region; + +/** + * Clipboard commands. + * + * @author sk89q + */ +public class ClipboardCommands { + private final WorldEdit we; + + public ClipboardCommands(WorldEdit we) { + this.we = we; + } + + @Command( + aliases = { "/copy" }, + flags = "e", + desc = "Copy the selection to the clipboard", + help = "Copy the selection to the clipboard\n" + + "Flags:\n" + + " -e controls whether entities are copied\n" + + "WARNING: Pasting entities cannot yet be undone!", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.clipboard.copy") + public void copy(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + Region region = session.getSelection(player.getWorld()); + Vector min = region.getMinimumPoint(); + Vector max = region.getMaximumPoint(); + Vector pos = session.getPlacementPosition(player); + + CuboidClipboard clipboard = new CuboidClipboard( + max.subtract(min).add(Vector.ONE), + min, min.subtract(pos)); + + if (region instanceof CuboidRegion) { + clipboard.copy(editSession); + } else { + clipboard.copy(editSession, region); + } + + if (args.hasFlag('e')) { + for (LocalEntity entity : player.getWorld().getEntities(region)) { + clipboard.storeEntity(entity); + } + } + session.setClipboard(clipboard); + + player.print("Block(s) copied."); + } + + @Command( + aliases = { "/cut" }, + usage = "[leave-id]", + desc = "Cut the selection to the clipboard", + help = "Copy the selection to the clipboard\n" + + "Flags:\n" + + " -e controls whether entities are copied\n" + + "WARNING: Cutting and pasting entities cannot yet be undone!", + flags = "e", + min = 0, + max = 1 + ) + @CommandPermissions("worldedit.clipboard.cut") + @Logging(REGION) + public void cut(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + BaseBlock block = new BaseBlock(BlockID.AIR); + LocalWorld world = player.getWorld(); + + if (args.argsLength() > 0) { + block = we.getBlock(player, args.getString(0)); + } + + Region region = session.getSelection(world); + Vector min = region.getMinimumPoint(); + Vector max = region.getMaximumPoint(); + Vector pos = session.getPlacementPosition(player); + + CuboidClipboard clipboard = new CuboidClipboard( + max.subtract(min).add(Vector.ONE), + min, min.subtract(pos)); + + if (region instanceof CuboidRegion) { + clipboard.copy(editSession); + } else { + clipboard.copy(editSession, region); + } + + if (args.hasFlag('e')) { + LocalEntity[] entities = world.getEntities(region); + for (LocalEntity entity : entities) { + clipboard.storeEntity(entity); + } + world.killEntities(entities); + } + session.setClipboard(clipboard); + + editSession.setBlocks(region, block); + player.print("Block(s) cut."); + } + + @Command( + aliases = { "/paste" }, + usage = "", + flags = "sao", + desc = "Paste the clipboard's contents", + help = + "Pastes the clipboard's contents.\n" + + "Flags:\n" + + " -a skips air blocks\n" + + " -o pastes at the original position\n" + + " -s selects the region after pasting", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.clipboard.paste") + @Logging(PLACEMENT) + public void paste(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + boolean atOrigin = args.hasFlag('o'); + boolean pasteNoAir = args.hasFlag('a'); + + CuboidClipboard clipboard = session.getClipboard(); + + Vector pos = atOrigin ? session.getClipboard().getOrigin() + : session.getPlacementPosition(player); + + if (atOrigin) { + clipboard.place(editSession, pos, pasteNoAir); + clipboard.pasteEntities(pos); + player.findFreePosition(); + player.print("Pasted to copy origin. Undo with //undo"); + } else { + clipboard.paste(editSession, pos, pasteNoAir, true); + player.findFreePosition(); + player.print("Pasted relative to you. Undo with //undo"); + } + + if (args.hasFlag('s')) { + LocalWorld world = player.getWorld(); + Vector pos2 = pos.add(clipboard.getSize().subtract(1, 1, 1)); + if (!atOrigin) { + pos2 = pos2.add(clipboard.getOffset()); + pos = pos.add(clipboard.getOffset()); + } + session.setRegionSelector(world, new CuboidRegionSelector(world, pos, pos2)); + session.getRegionSelector(world).learnChanges(); + session.getRegionSelector(world).explainRegionAdjust(player, session); + } + } + + @Command( + aliases = { "/rotate" }, + usage = "", + desc = "Rotate the contents of the clipboard", + min = 1, + max = 1 + ) + @CommandPermissions("worldedit.clipboard.rotate") + public void rotate(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + int angle = args.getInteger(0); + + if (angle % 90 == 0) { + CuboidClipboard clipboard = session.getClipboard(); + clipboard.rotate2D(angle); + player.print("Clipboard rotated by " + angle + " degrees."); + } else { + player.printError("Angles must be divisible by 90 degrees."); + } + } + + @Command( + aliases = { "/flip" }, + usage = "[dir]", + flags = "p", + desc = "Flip the contents of the clipboard.", + help = + "Flips the contents of the clipboard.\n" + + "The -p flag flips the selection around the player,\n" + + "instead of the selections center.", + min = 0, + max = 1 + ) + @CommandPermissions("worldedit.clipboard.flip") + public void flip(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + CuboidClipboard.FlipDirection dir = we.getFlipDirection(player, + args.argsLength() > 0 ? args.getString(0).toLowerCase() : "me"); + + CuboidClipboard clipboard = session.getClipboard(); + clipboard.flip(dir, args.hasFlag('p')); + player.print("Clipboard flipped."); + } + + @Command( + aliases = { "/load" }, + usage = "", + desc = "Load a schematic into your clipboard", + min = 0, + max = 1 + ) + @Deprecated + @CommandPermissions("worldedit.clipboard.load") + public void load(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + player.printError("This command is no longer used. See //schematic load."); + } + + @Command( + aliases = { "/save" }, + usage = "", + desc = "Save a schematic into your clipboard", + min = 0, + max = 1 + ) + @Deprecated + @CommandPermissions("worldedit.clipboard.save") + public void save(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + player.printError("This command is no longer used. See //schematic save."); + } + + @Command( + aliases = { "/schematic", "/schem"}, + desc = "Schematic-related commands" + ) + @NestedCommand(SchematicCommands.class) + public void schematic() {} + + @Command( + aliases = { "clearclipboard" }, + usage = "", + desc = "Clear your clipboard", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.clipboard.clear") + public void clearClipboard(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + session.setClipboard(null); + player.print("Clipboard cleared."); + } +} diff --git a/src/main/java/com/sk89q/worldedit/commands/GeneralCommands.java b/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/commands/GeneralCommands.java rename to src/main/java/com/sk89q/worldedit/command/GeneralCommands.java index 2fc8fd4f3..3ca64194f 100644 --- a/src/main/java/com/sk89q/worldedit/commands/GeneralCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java @@ -1,234 +1,234 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.commands; - -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.Console; -import com.sk89q.minecraft.util.commands.NestedCommand; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.LocalConfiguration; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.blocks.ItemType; -import com.sk89q.worldedit.masks.Mask; - -/** - * General WorldEdit commands. - * - * @author sk89q - */ -public class GeneralCommands { - private final WorldEdit we; - - public GeneralCommands(WorldEdit we) { - this.we = we; - } - - @Command( - aliases = { "/limit" }, - usage = "", - desc = "Modify block change limit", - min = 1, - max = 1 - ) - @CommandPermissions("worldedit.limit") - public void limit(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - LocalConfiguration config = we.getConfiguration(); - - int limit = Math.max(-1, args.getInteger(0)); - if (!player.hasPermission("worldedit.limit.unrestricted") - && config.maxChangeLimit > -1) { - if (limit > config.maxChangeLimit) { - player.printError("Your maximum allowable limit is " - + config.maxChangeLimit + "."); - return; - } - } - - session.setBlockChangeLimit(limit); - player.print("Block change limit set to " + limit + "."); - } - - @Command( - aliases = { "/fast" }, - usage = "[on|off]", - desc = "Toggle fast mode", - min = 0, - max = 1 - ) - @CommandPermissions("worldedit.fast") - public void fast(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - String newState = args.getString(0, null); - if (session.hasFastMode()) { - if ("on".equals(newState)) { - player.printError("Fast mode already enabled."); - return; - } - - session.setFastMode(false); - player.print("Fast mode disabled."); - } else { - if ("off".equals(newState)) { - player.printError("Fast mode already disabled."); - return; - } - - session.setFastMode(true); - player.print("Fast mode enabled. Lighting in the affected chunks may be wrong and/or you may need to rejoin to see changes."); - } - } - - @Command( - aliases = { "/gmask", "gmask" }, - usage = "[mask]", - desc = "Set the global mask", - min = 0, - max = -1 - ) - @CommandPermissions("worldedit.global-mask") - public void gmask(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - if (args.argsLength() == 0) { - session.setMask(null); - player.print("Global mask disabled."); - } else { - Mask mask = we.getBlockMask(player, session, args.getJoinedStrings(0)); - session.setMask(mask); - player.print("Global mask set."); - } - } - - @Command( - aliases = { "/toggleplace", "toggleplace" }, - usage = "", - desc = "Switch between your position and pos1 for placement", - min = 0, - max = 0 - ) - public void togglePlace(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - if (session.togglePlacementPosition()) { - player.print("Now placing at pos #1."); - } else { - player.print("Now placing at the block you stand in."); - } - } - - @Command( - aliases = { "/searchitem", "/l", "/search", "searchitem" }, - usage = "", - flags = "bi", - desc = "Search for an item", - help = - "Searches for an item.\n" + - "Flags:\n" + - " -b only search for blocks\n" + - " -i only search for items", - min = 1, - max = 1 - ) - @Console - public void searchItem(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - String query = args.getString(0).trim().toLowerCase(); - boolean blocksOnly = args.hasFlag('b'); - boolean itemsOnly = args.hasFlag('i'); - - try { - int id = Integer.parseInt(query); - - ItemType type = ItemType.fromID(id); - - if (type != null) { - player.print("#" + type.getID() + " (" + type.getName() + ")"); - } else { - player.printError("No item found by ID " + id); - } - - return; - } catch (NumberFormatException e) { - } - - if (query.length() <= 2) { - player.printError("Enter a longer search string (len > 2)."); - return; - } - - if (!blocksOnly && !itemsOnly) { - player.print("Searching for: " + query); - } else if (blocksOnly && itemsOnly) { - player.printError("You cannot use both the 'b' and 'i' flags simultaneously."); - return; - } else if (blocksOnly) { - player.print("Searching for blocks: " + query); - } else { - player.print("Searching for items: " + query); - } - - int found = 0; - - for (ItemType type : ItemType.values()) { - if (found >= 15) { - player.print("Too many results!"); - break; - } - - if (blocksOnly && type.getID() > 255) { - continue; - } - - if (itemsOnly && type.getID() <= 255) { - continue; - } - - for (String alias : type.getAliases()) { - if (alias.contains(query)) { - player.print("#" + type.getID() + " (" + type.getName() + ")"); - ++found; - break; - } - } - } - - if (found == 0) { - player.printError("No items found."); - } - } - - @Command( - aliases = { "we", "worldedit" }, - desc = "WorldEdit commands" - ) - @NestedCommand(WorldEditCommands.class) - @Console - public void we(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command; + +import com.sk89q.minecraft.util.commands.Command; +import com.sk89q.minecraft.util.commands.CommandContext; +import com.sk89q.minecraft.util.commands.CommandPermissions; +import com.sk89q.minecraft.util.commands.Console; +import com.sk89q.minecraft.util.commands.NestedCommand; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.ItemType; +import com.sk89q.worldedit.masks.Mask; + +/** + * General WorldEdit commands. + * + * @author sk89q + */ +public class GeneralCommands { + private final WorldEdit we; + + public GeneralCommands(WorldEdit we) { + this.we = we; + } + + @Command( + aliases = { "/limit" }, + usage = "", + desc = "Modify block change limit", + min = 1, + max = 1 + ) + @CommandPermissions("worldedit.limit") + public void limit(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + LocalConfiguration config = we.getConfiguration(); + + int limit = Math.max(-1, args.getInteger(0)); + if (!player.hasPermission("worldedit.limit.unrestricted") + && config.maxChangeLimit > -1) { + if (limit > config.maxChangeLimit) { + player.printError("Your maximum allowable limit is " + + config.maxChangeLimit + "."); + return; + } + } + + session.setBlockChangeLimit(limit); + player.print("Block change limit set to " + limit + "."); + } + + @Command( + aliases = { "/fast" }, + usage = "[on|off]", + desc = "Toggle fast mode", + min = 0, + max = 1 + ) + @CommandPermissions("worldedit.fast") + public void fast(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + String newState = args.getString(0, null); + if (session.hasFastMode()) { + if ("on".equals(newState)) { + player.printError("Fast mode already enabled."); + return; + } + + session.setFastMode(false); + player.print("Fast mode disabled."); + } else { + if ("off".equals(newState)) { + player.printError("Fast mode already disabled."); + return; + } + + session.setFastMode(true); + player.print("Fast mode enabled. Lighting in the affected chunks may be wrong and/or you may need to rejoin to see changes."); + } + } + + @Command( + aliases = { "/gmask", "gmask" }, + usage = "[mask]", + desc = "Set the global mask", + min = 0, + max = -1 + ) + @CommandPermissions("worldedit.global-mask") + public void gmask(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + if (args.argsLength() == 0) { + session.setMask(null); + player.print("Global mask disabled."); + } else { + Mask mask = we.getBlockMask(player, session, args.getJoinedStrings(0)); + session.setMask(mask); + player.print("Global mask set."); + } + } + + @Command( + aliases = { "/toggleplace", "toggleplace" }, + usage = "", + desc = "Switch between your position and pos1 for placement", + min = 0, + max = 0 + ) + public void togglePlace(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + if (session.togglePlacementPosition()) { + player.print("Now placing at pos #1."); + } else { + player.print("Now placing at the block you stand in."); + } + } + + @Command( + aliases = { "/searchitem", "/l", "/search", "searchitem" }, + usage = "", + flags = "bi", + desc = "Search for an item", + help = + "Searches for an item.\n" + + "Flags:\n" + + " -b only search for blocks\n" + + " -i only search for items", + min = 1, + max = 1 + ) + @Console + public void searchItem(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + String query = args.getString(0).trim().toLowerCase(); + boolean blocksOnly = args.hasFlag('b'); + boolean itemsOnly = args.hasFlag('i'); + + try { + int id = Integer.parseInt(query); + + ItemType type = ItemType.fromID(id); + + if (type != null) { + player.print("#" + type.getID() + " (" + type.getName() + ")"); + } else { + player.printError("No item found by ID " + id); + } + + return; + } catch (NumberFormatException e) { + } + + if (query.length() <= 2) { + player.printError("Enter a longer search string (len > 2)."); + return; + } + + if (!blocksOnly && !itemsOnly) { + player.print("Searching for: " + query); + } else if (blocksOnly && itemsOnly) { + player.printError("You cannot use both the 'b' and 'i' flags simultaneously."); + return; + } else if (blocksOnly) { + player.print("Searching for blocks: " + query); + } else { + player.print("Searching for items: " + query); + } + + int found = 0; + + for (ItemType type : ItemType.values()) { + if (found >= 15) { + player.print("Too many results!"); + break; + } + + if (blocksOnly && type.getID() > 255) { + continue; + } + + if (itemsOnly && type.getID() <= 255) { + continue; + } + + for (String alias : type.getAliases()) { + if (alias.contains(query)) { + player.print("#" + type.getID() + " (" + type.getName() + ")"); + ++found; + break; + } + } + } + + if (found == 0) { + player.printError("No items found."); + } + } + + @Command( + aliases = { "we", "worldedit" }, + desc = "WorldEdit commands" + ) + @NestedCommand(WorldEditCommands.class) + @Console + public void we(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + } +} diff --git a/src/main/java/com/sk89q/worldedit/commands/GenerationCommands.java b/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/commands/GenerationCommands.java rename to src/main/java/com/sk89q/worldedit/command/GenerationCommands.java index d904e5f1b..cb5dc2ea0 100644 --- a/src/main/java/com/sk89q/worldedit/commands/GenerationCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java @@ -1,487 +1,486 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.commands; - -import static com.sk89q.minecraft.util.commands.Logging.LogMode.ALL; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.PLACEMENT; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.POSITION; - -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.Logging; -import com.sk89q.worldedit.BiomeType; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.Vector2D; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.expression.ExpressionException; -import com.sk89q.worldedit.patterns.Pattern; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.util.TreeGenerator; - -/** - * Generation commands. - * - * @author sk89q - */ -public class GenerationCommands { - private final WorldEdit we; - - public GenerationCommands(WorldEdit we) { - this.we = we; - } - - @Command( - aliases = { "/hcyl" }, - usage = " [,] [height]", - desc = "Generates a hollow cylinder.", - help = - "Generates a hollow cylinder.\n" + - "By specifying 2 radii, separated by a comma,\n" + - "you can generate elliptical cylinders.\n" + - "The 1st radius is north/south, the 2nd radius is east/west.", - min = 2, - max = 3 - ) - @CommandPermissions("worldedit.generation.cylinder") - @Logging(PLACEMENT) - public void hcyl(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - Pattern block = we.getBlockPattern(player, args.getString(0)); - String[] radiuses = args.getString(1).split(","); - final double radiusX, radiusZ; - switch (radiuses.length) { - case 1: - radiusX = radiusZ = Math.max(1, Double.parseDouble(radiuses[0])); - break; - - case 2: - radiusX = Math.max(1, Double.parseDouble(radiuses[0])); - radiusZ = Math.max(1, Double.parseDouble(radiuses[1])); - break; - - default: - player.printError("You must either specify 1 or 2 radius values."); - return; - } - int height = args.argsLength() > 2 ? args.getInteger(2) : 1; - - we.checkMaxRadius(radiusX); - we.checkMaxRadius(radiusZ); - we.checkMaxRadius(height); - - Vector pos = session.getPlacementPosition(player); - int affected = editSession.makeCylinder(pos, block, radiusX, radiusZ, height, false); - player.print(affected + " block(s) have been created."); - } - - @Command( - aliases = { "/cyl" }, - usage = " [,] [height]", - desc = "Generates a cylinder.", - help = - "Generates a cylinder.\n" + - "By specifying 2 radii, separated by a comma,\n" + - "you can generate elliptical cylinders.\n" + - "The 1st radius is north/south, the 2nd radius is east/west.", - min = 2, - max = 3 - ) - @CommandPermissions("worldedit.generation.cylinder") - @Logging(PLACEMENT) - public void cyl(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - Pattern block = we.getBlockPattern(player, args.getString(0)); - String[] radiuses = args.getString(1).split(","); - final double radiusX, radiusZ; - switch (radiuses.length) { - case 1: - radiusX = radiusZ = Math.max(1, Double.parseDouble(radiuses[0])); - break; - - case 2: - radiusX = Math.max(1, Double.parseDouble(radiuses[0])); - radiusZ = Math.max(1, Double.parseDouble(radiuses[1])); - break; - - default: - player.printError("You must either specify 1 or 2 radius values."); - return; - } - int height = args.argsLength() > 2 ? args.getInteger(2) : 1; - - we.checkMaxRadius(radiusX); - we.checkMaxRadius(radiusZ); - we.checkMaxRadius(height); - - Vector pos = session.getPlacementPosition(player); - int affected = editSession.makeCylinder(pos, block, radiusX, radiusZ, height, true); - player.print(affected + " block(s) have been created."); - } - - @Command( - aliases = { "/hsphere" }, - usage = " [,,] [raised?]", - desc = "Generates a hollow sphere.", - help = - "Generates a hollow sphere.\n" + - "By specifying 3 radii, separated by commas,\n" + - "you can generate an ellipsoid. The order of the ellipsoid radii\n" + - "is north/south, up/down, east/west.", - min = 2, - max = 3 - ) - @CommandPermissions("worldedit.generation.sphere") - @Logging(PLACEMENT) - public void hsphere(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - final Pattern block = we.getBlockPattern(player, args.getString(0)); - String[] radiuses = args.getString(1).split(","); - final double radiusX, radiusY, radiusZ; - switch (radiuses.length) { - case 1: - radiusX = radiusY = radiusZ = Math.max(1, Double.parseDouble(radiuses[0])); - break; - - case 3: - radiusX = Math.max(1, Double.parseDouble(radiuses[0])); - radiusY = Math.max(1, Double.parseDouble(radiuses[1])); - radiusZ = Math.max(1, Double.parseDouble(radiuses[2])); - break; - - default: - player.printError("You must either specify 1 or 3 radius values."); - return; - } - - we.checkMaxRadius(radiusX); - we.checkMaxRadius(radiusY); - we.checkMaxRadius(radiusZ); - - final boolean raised; - if (args.argsLength() > 2) { - raised = args.getString(2).equalsIgnoreCase("true") || args.getString(2).equalsIgnoreCase("yes"); - } else { - raised = false; - } - - Vector pos = session.getPlacementPosition(player); - if (raised) { - pos = pos.add(0, radiusY, 0); - } - - int affected = editSession.makeSphere(pos, block, radiusX, radiusY, radiusZ, false); - player.findFreePosition(); - player.print(affected + " block(s) have been created."); - } - - @Command( - aliases = { "/sphere" }, - usage = " [,,] [raised?]", - desc = "Generates a filled sphere.", - help = - "Generates a filled sphere.\n" + - "By specifying 3 radii, separated by commas,\n" + - "you can generate an ellipsoid. The order of the ellipsoid radii\n" + - "is north/south, up/down, east/west.", - min = 2, - max = 3 - ) - @CommandPermissions("worldedit.generation.sphere") - @Logging(PLACEMENT) - public void sphere(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - Pattern block = we.getBlockPattern(player, args.getString(0)); - String[] radiuses = args.getString(1).split(","); - final double radiusX, radiusY, radiusZ; - switch (radiuses.length) { - case 1: - radiusX = radiusY = radiusZ = Math.max(1, Double.parseDouble(radiuses[0])); - break; - - case 3: - radiusX = Math.max(1, Double.parseDouble(radiuses[0])); - radiusY = Math.max(1, Double.parseDouble(radiuses[1])); - radiusZ = Math.max(1, Double.parseDouble(radiuses[2])); - break; - - default: - player.printError("You must either specify 1 or 3 radius values."); - return; - } - - we.checkMaxRadius(radiusX); - we.checkMaxRadius(radiusY); - we.checkMaxRadius(radiusZ); - - final boolean raised; - if (args.argsLength() > 2) { - raised = args.getString(2).equalsIgnoreCase("true") || args.getString(2).equalsIgnoreCase("yes"); - } else { - raised = false; - } - - Vector pos = session.getPlacementPosition(player); - if (raised) { - pos = pos.add(0, radiusY, 0); - } - - int affected = editSession.makeSphere(pos, block, radiusX, radiusY, radiusZ, true); - player.findFreePosition(); - player.print(affected + " block(s) have been created."); - } - - @Command( - aliases = { "forestgen" }, - usage = "[size] [type] [density]", - desc = "Generate a forest", - min = 0, - max = 3 - ) - @CommandPermissions("worldedit.generation.forest") - @Logging(POSITION) - @SuppressWarnings("deprecation") - public void forestGen(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 10; - TreeGenerator.TreeType type = args.argsLength() > 1 ? - TreeGenerator.lookup(args.getString(1)) - : TreeGenerator.TreeType.TREE; - double density = args.argsLength() > 2 ? args.getDouble(2) / 100 : 0.05; - - if (type == null) { - player.printError("Tree type '" + args.getString(1) + "' is unknown."); - return; - } - - int affected = editSession.makeForest(session.getPlacementPosition(player), - size, density, new TreeGenerator(type)); - player.print(affected + " trees created."); - } - - @Command( - aliases = { "pumpkins" }, - usage = "[size]", - desc = "Generate pumpkin patches", - min = 0, - max = 1 - ) - @CommandPermissions("worldedit.generation.pumpkins") - @Logging(POSITION) - public void pumpkins(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 10; - - int affected = editSession.makePumpkinPatches(session.getPlacementPosition(player), size); - player.print(affected + " pumpkin patches created."); - } - - @Command( - aliases = { "/pyramid" }, - usage = " ", - desc = "Generate a filled pyramid", - min = 2, - max = 2 - ) - @CommandPermissions("worldedit.generation.pyramid") - @Logging(PLACEMENT) - public void pyramid(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - Pattern block = we.getBlockPattern(player, args.getString(0)); - int size = Math.max(1, args.getInteger(1)); - Vector pos = session.getPlacementPosition(player); - - we.checkMaxRadius(size); - - int affected = editSession.makePyramid(pos, block, size, true); - - player.findFreePosition(); - player.print(affected + " block(s) have been created."); - } - - @Command( - aliases = { "/hpyramid" }, - usage = " ", - desc = "Generate a hollow pyramid", - min = 2, - max = 2 - ) - @CommandPermissions("worldedit.generation.pyramid") - @Logging(PLACEMENT) - public void hpyramid(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - Pattern block = we.getBlockPattern(player, args.getString(0)); - int size = Math.max(1, args.getInteger(1)); - Vector pos = session.getPlacementPosition(player); - - we.checkMaxRadius(size); - - int affected = editSession.makePyramid(pos, block, size, false); - - player.findFreePosition(); - player.print(affected + " block(s) have been created."); - } - - @Command( - aliases = { "/generate", "/gen", "/g" }, - usage = " ", - desc = "Generates a shape according to a formula.", - help = - "Generates a shape according to a formula that is expected to\n" + - "return positive numbers (true) if the point is inside the shape\n" + - "Optionally set type/data to the desired block.\n" + - "Flags:\n" + - " -h to generate a hollow shape\n" + - " -r to use raw minecraft coordinates\n" + - " -o is like -r, except offset from placement.\n" + - " -c is like -r, except offset selection center.\n" + - "If neither -r nor -o is given, the selection is mapped to -1..1\n" + - "See also tinyurl.com/wesyntax.", - flags = "hroc", - min = 2, - max = -1 - ) - @CommandPermissions("worldedit.generation.shape") - @Logging(ALL) - public void generate(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - final Pattern pattern = we.getBlockPattern(player, args.getString(0)); - final Region region = session.getSelection(player.getWorld()); - - final boolean hollow = args.hasFlag('h'); - - final String expression = args.getJoinedStrings(1); - - final Vector zero; - Vector unit; - - if (args.hasFlag('r')) { - zero = Vector.ZERO; - unit = Vector.ONE; - } else if (args.hasFlag('o')) { - zero = session.getPlacementPosition(player); - unit = Vector.ONE; - } else if (args.hasFlag('c')) { - final Vector min = region.getMinimumPoint(); - final Vector max = region.getMaximumPoint(); - - zero = max.add(min).multiply(0.5); - unit = Vector.ONE; - } else { - final Vector min = region.getMinimumPoint(); - final Vector max = region.getMaximumPoint(); - - zero = max.add(min).multiply(0.5); - unit = max.subtract(zero); - - if (unit.getX() == 0) unit = unit.setX(1.0); - if (unit.getY() == 0) unit = unit.setY(1.0); - if (unit.getZ() == 0) unit = unit.setZ(1.0); - } - - try { - final int affected = editSession.makeShape(region, zero, unit, pattern, expression, hollow); - player.findFreePosition(); - player.print(affected + " block(s) have been created."); - } catch (ExpressionException e) { - player.printError(e.getMessage()); - } - } - - @Command( - aliases = { "/generatebiome", "/genbiome", "/gb" }, - usage = " ", - desc = "Sets biome according to a formula.", - help = - "Generates a shape according to a formula that is expected to\n" + - "return positive numbers (true) if the point is inside the shape\n" + - "Optionally set type/data to the desired block.\n" + - "Flags:\n" + - " -h to generate a hollow shape\n" + - " -r to use raw minecraft coordinates\n" + - " -o is like -r, except offset from placement.\n" + - " -c is like -r, except offset selection center.\n" + - "If neither -r nor -o is given, the selection is mapped to -1..1\n" + - "See also tinyurl.com/wesyntax.", - flags = "hroc", - min = 2, - max = -1 - ) - @CommandPermissions({"worldedit.generation.shape", "worldedit.biome.set"}) - @Logging(ALL) - public void generateBiome(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - final BiomeType target = we.getServer().getBiomes().get(args.getString(0)); - final Region region = session.getSelection(player.getWorld()); - - final boolean hollow = args.hasFlag('h'); - - final String expression = args.getJoinedStrings(1); - - final Vector zero; - Vector unit; - - if (args.hasFlag('r')) { - zero = Vector.ZERO; - unit = Vector.ONE; - } else if (args.hasFlag('o')) { - zero = session.getPlacementPosition(player); - unit = Vector.ONE; - } else if (args.hasFlag('c')) { - final Vector min = region.getMinimumPoint(); - final Vector max = region.getMaximumPoint(); - - zero = max.add(min).multiply(0.5); - unit = Vector.ONE; - } else { - final Vector min = region.getMinimumPoint(); - final Vector max = region.getMaximumPoint(); - - zero = max.add(min).multiply(0.5); - unit = max.subtract(zero); - - if (unit.getX() == 0) unit = unit.setX(1.0); - if (unit.getY() == 0) unit = unit.setY(1.0); - if (unit.getZ() == 0) unit = unit.setZ(1.0); - } - - try { - final int affected = editSession.makeBiomeShape(region, zero, unit, target, expression, hollow); - player.findFreePosition(); - player.print("Biome changed to " + target.getName() + ". " + affected + " columns affected."); - } catch (ExpressionException e) { - player.printError(e.getMessage()); - } - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command; + +import static com.sk89q.minecraft.util.commands.Logging.LogMode.ALL; +import static com.sk89q.minecraft.util.commands.Logging.LogMode.PLACEMENT; +import static com.sk89q.minecraft.util.commands.Logging.LogMode.POSITION; + +import com.sk89q.minecraft.util.commands.Command; +import com.sk89q.minecraft.util.commands.CommandContext; +import com.sk89q.minecraft.util.commands.CommandPermissions; +import com.sk89q.minecraft.util.commands.Logging; +import com.sk89q.worldedit.BiomeType; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.internal.expression.ExpressionException; +import com.sk89q.worldedit.patterns.Pattern; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.TreeGenerator; + +/** + * Generation commands. + * + * @author sk89q + */ +public class GenerationCommands { + private final WorldEdit we; + + public GenerationCommands(WorldEdit we) { + this.we = we; + } + + @Command( + aliases = { "/hcyl" }, + usage = " [,] [height]", + desc = "Generates a hollow cylinder.", + help = + "Generates a hollow cylinder.\n" + + "By specifying 2 radii, separated by a comma,\n" + + "you can generate elliptical cylinders.\n" + + "The 1st radius is north/south, the 2nd radius is east/west.", + min = 2, + max = 3 + ) + @CommandPermissions("worldedit.generation.cylinder") + @Logging(PLACEMENT) + public void hcyl(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + Pattern block = we.getBlockPattern(player, args.getString(0)); + String[] radiuses = args.getString(1).split(","); + final double radiusX, radiusZ; + switch (radiuses.length) { + case 1: + radiusX = radiusZ = Math.max(1, Double.parseDouble(radiuses[0])); + break; + + case 2: + radiusX = Math.max(1, Double.parseDouble(radiuses[0])); + radiusZ = Math.max(1, Double.parseDouble(radiuses[1])); + break; + + default: + player.printError("You must either specify 1 or 2 radius values."); + return; + } + int height = args.argsLength() > 2 ? args.getInteger(2) : 1; + + we.checkMaxRadius(radiusX); + we.checkMaxRadius(radiusZ); + we.checkMaxRadius(height); + + Vector pos = session.getPlacementPosition(player); + int affected = editSession.makeCylinder(pos, block, radiusX, radiusZ, height, false); + player.print(affected + " block(s) have been created."); + } + + @Command( + aliases = { "/cyl" }, + usage = " [,] [height]", + desc = "Generates a cylinder.", + help = + "Generates a cylinder.\n" + + "By specifying 2 radii, separated by a comma,\n" + + "you can generate elliptical cylinders.\n" + + "The 1st radius is north/south, the 2nd radius is east/west.", + min = 2, + max = 3 + ) + @CommandPermissions("worldedit.generation.cylinder") + @Logging(PLACEMENT) + public void cyl(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + Pattern block = we.getBlockPattern(player, args.getString(0)); + String[] radiuses = args.getString(1).split(","); + final double radiusX, radiusZ; + switch (radiuses.length) { + case 1: + radiusX = radiusZ = Math.max(1, Double.parseDouble(radiuses[0])); + break; + + case 2: + radiusX = Math.max(1, Double.parseDouble(radiuses[0])); + radiusZ = Math.max(1, Double.parseDouble(radiuses[1])); + break; + + default: + player.printError("You must either specify 1 or 2 radius values."); + return; + } + int height = args.argsLength() > 2 ? args.getInteger(2) : 1; + + we.checkMaxRadius(radiusX); + we.checkMaxRadius(radiusZ); + we.checkMaxRadius(height); + + Vector pos = session.getPlacementPosition(player); + int affected = editSession.makeCylinder(pos, block, radiusX, radiusZ, height, true); + player.print(affected + " block(s) have been created."); + } + + @Command( + aliases = { "/hsphere" }, + usage = " [,,] [raised?]", + desc = "Generates a hollow sphere.", + help = + "Generates a hollow sphere.\n" + + "By specifying 3 radii, separated by commas,\n" + + "you can generate an ellipsoid. The order of the ellipsoid radii\n" + + "is north/south, up/down, east/west.", + min = 2, + max = 3 + ) + @CommandPermissions("worldedit.generation.sphere") + @Logging(PLACEMENT) + public void hsphere(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + final Pattern block = we.getBlockPattern(player, args.getString(0)); + String[] radiuses = args.getString(1).split(","); + final double radiusX, radiusY, radiusZ; + switch (radiuses.length) { + case 1: + radiusX = radiusY = radiusZ = Math.max(1, Double.parseDouble(radiuses[0])); + break; + + case 3: + radiusX = Math.max(1, Double.parseDouble(radiuses[0])); + radiusY = Math.max(1, Double.parseDouble(radiuses[1])); + radiusZ = Math.max(1, Double.parseDouble(radiuses[2])); + break; + + default: + player.printError("You must either specify 1 or 3 radius values."); + return; + } + + we.checkMaxRadius(radiusX); + we.checkMaxRadius(radiusY); + we.checkMaxRadius(radiusZ); + + final boolean raised; + if (args.argsLength() > 2) { + raised = args.getString(2).equalsIgnoreCase("true") || args.getString(2).equalsIgnoreCase("yes"); + } else { + raised = false; + } + + Vector pos = session.getPlacementPosition(player); + if (raised) { + pos = pos.add(0, radiusY, 0); + } + + int affected = editSession.makeSphere(pos, block, radiusX, radiusY, radiusZ, false); + player.findFreePosition(); + player.print(affected + " block(s) have been created."); + } + + @Command( + aliases = { "/sphere" }, + usage = " [,,] [raised?]", + desc = "Generates a filled sphere.", + help = + "Generates a filled sphere.\n" + + "By specifying 3 radii, separated by commas,\n" + + "you can generate an ellipsoid. The order of the ellipsoid radii\n" + + "is north/south, up/down, east/west.", + min = 2, + max = 3 + ) + @CommandPermissions("worldedit.generation.sphere") + @Logging(PLACEMENT) + public void sphere(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + Pattern block = we.getBlockPattern(player, args.getString(0)); + String[] radiuses = args.getString(1).split(","); + final double radiusX, radiusY, radiusZ; + switch (radiuses.length) { + case 1: + radiusX = radiusY = radiusZ = Math.max(1, Double.parseDouble(radiuses[0])); + break; + + case 3: + radiusX = Math.max(1, Double.parseDouble(radiuses[0])); + radiusY = Math.max(1, Double.parseDouble(radiuses[1])); + radiusZ = Math.max(1, Double.parseDouble(radiuses[2])); + break; + + default: + player.printError("You must either specify 1 or 3 radius values."); + return; + } + + we.checkMaxRadius(radiusX); + we.checkMaxRadius(radiusY); + we.checkMaxRadius(radiusZ); + + final boolean raised; + if (args.argsLength() > 2) { + raised = args.getString(2).equalsIgnoreCase("true") || args.getString(2).equalsIgnoreCase("yes"); + } else { + raised = false; + } + + Vector pos = session.getPlacementPosition(player); + if (raised) { + pos = pos.add(0, radiusY, 0); + } + + int affected = editSession.makeSphere(pos, block, radiusX, radiusY, radiusZ, true); + player.findFreePosition(); + player.print(affected + " block(s) have been created."); + } + + @Command( + aliases = { "forestgen" }, + usage = "[size] [type] [density]", + desc = "Generate a forest", + min = 0, + max = 3 + ) + @CommandPermissions("worldedit.generation.forest") + @Logging(POSITION) + @SuppressWarnings("deprecation") + public void forestGen(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 10; + TreeGenerator.TreeType type = args.argsLength() > 1 ? + TreeGenerator.lookup(args.getString(1)) + : TreeGenerator.TreeType.TREE; + double density = args.argsLength() > 2 ? args.getDouble(2) / 100 : 0.05; + + if (type == null) { + player.printError("Tree type '" + args.getString(1) + "' is unknown."); + return; + } + + int affected = editSession.makeForest(session.getPlacementPosition(player), + size, density, new TreeGenerator(type)); + player.print(affected + " trees created."); + } + + @Command( + aliases = { "pumpkins" }, + usage = "[size]", + desc = "Generate pumpkin patches", + min = 0, + max = 1 + ) + @CommandPermissions("worldedit.generation.pumpkins") + @Logging(POSITION) + public void pumpkins(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 10; + + int affected = editSession.makePumpkinPatches(session.getPlacementPosition(player), size); + player.print(affected + " pumpkin patches created."); + } + + @Command( + aliases = { "/pyramid" }, + usage = " ", + desc = "Generate a filled pyramid", + min = 2, + max = 2 + ) + @CommandPermissions("worldedit.generation.pyramid") + @Logging(PLACEMENT) + public void pyramid(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + Pattern block = we.getBlockPattern(player, args.getString(0)); + int size = Math.max(1, args.getInteger(1)); + Vector pos = session.getPlacementPosition(player); + + we.checkMaxRadius(size); + + int affected = editSession.makePyramid(pos, block, size, true); + + player.findFreePosition(); + player.print(affected + " block(s) have been created."); + } + + @Command( + aliases = { "/hpyramid" }, + usage = " ", + desc = "Generate a hollow pyramid", + min = 2, + max = 2 + ) + @CommandPermissions("worldedit.generation.pyramid") + @Logging(PLACEMENT) + public void hpyramid(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + Pattern block = we.getBlockPattern(player, args.getString(0)); + int size = Math.max(1, args.getInteger(1)); + Vector pos = session.getPlacementPosition(player); + + we.checkMaxRadius(size); + + int affected = editSession.makePyramid(pos, block, size, false); + + player.findFreePosition(); + player.print(affected + " block(s) have been created."); + } + + @Command( + aliases = { "/generate", "/gen", "/g" }, + usage = " ", + desc = "Generates a shape according to a formula.", + help = + "Generates a shape according to a formula that is expected to\n" + + "return positive numbers (true) if the point is inside the shape\n" + + "Optionally set type/data to the desired block.\n" + + "Flags:\n" + + " -h to generate a hollow shape\n" + + " -r to use raw minecraft coordinates\n" + + " -o is like -r, except offset from placement.\n" + + " -c is like -r, except offset selection center.\n" + + "If neither -r nor -o is given, the selection is mapped to -1..1\n" + + "See also tinyurl.com/wesyntax.", + flags = "hroc", + min = 2, + max = -1 + ) + @CommandPermissions("worldedit.generation.shape") + @Logging(ALL) + public void generate(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + final Pattern pattern = we.getBlockPattern(player, args.getString(0)); + final Region region = session.getSelection(player.getWorld()); + + final boolean hollow = args.hasFlag('h'); + + final String expression = args.getJoinedStrings(1); + + final Vector zero; + Vector unit; + + if (args.hasFlag('r')) { + zero = Vector.ZERO; + unit = Vector.ONE; + } else if (args.hasFlag('o')) { + zero = session.getPlacementPosition(player); + unit = Vector.ONE; + } else if (args.hasFlag('c')) { + final Vector min = region.getMinimumPoint(); + final Vector max = region.getMaximumPoint(); + + zero = max.add(min).multiply(0.5); + unit = Vector.ONE; + } else { + final Vector min = region.getMinimumPoint(); + final Vector max = region.getMaximumPoint(); + + zero = max.add(min).multiply(0.5); + unit = max.subtract(zero); + + if (unit.getX() == 0) unit = unit.setX(1.0); + if (unit.getY() == 0) unit = unit.setY(1.0); + if (unit.getZ() == 0) unit = unit.setZ(1.0); + } + + try { + final int affected = editSession.makeShape(region, zero, unit, pattern, expression, hollow); + player.findFreePosition(); + player.print(affected + " block(s) have been created."); + } catch (ExpressionException e) { + player.printError(e.getMessage()); + } + } + + @Command( + aliases = { "/generatebiome", "/genbiome", "/gb" }, + usage = " ", + desc = "Sets biome according to a formula.", + help = + "Generates a shape according to a formula that is expected to\n" + + "return positive numbers (true) if the point is inside the shape\n" + + "Optionally set type/data to the desired block.\n" + + "Flags:\n" + + " -h to generate a hollow shape\n" + + " -r to use raw minecraft coordinates\n" + + " -o is like -r, except offset from placement.\n" + + " -c is like -r, except offset selection center.\n" + + "If neither -r nor -o is given, the selection is mapped to -1..1\n" + + "See also tinyurl.com/wesyntax.", + flags = "hroc", + min = 2, + max = -1 + ) + @CommandPermissions({"worldedit.generation.shape", "worldedit.biome.set"}) + @Logging(ALL) + public void generateBiome(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + final BiomeType target = we.getServer().getBiomes().get(args.getString(0)); + final Region region = session.getSelection(player.getWorld()); + + final boolean hollow = args.hasFlag('h'); + + final String expression = args.getJoinedStrings(1); + + final Vector zero; + Vector unit; + + if (args.hasFlag('r')) { + zero = Vector.ZERO; + unit = Vector.ONE; + } else if (args.hasFlag('o')) { + zero = session.getPlacementPosition(player); + unit = Vector.ONE; + } else if (args.hasFlag('c')) { + final Vector min = region.getMinimumPoint(); + final Vector max = region.getMaximumPoint(); + + zero = max.add(min).multiply(0.5); + unit = Vector.ONE; + } else { + final Vector min = region.getMinimumPoint(); + final Vector max = region.getMaximumPoint(); + + zero = max.add(min).multiply(0.5); + unit = max.subtract(zero); + + if (unit.getX() == 0) unit = unit.setX(1.0); + if (unit.getY() == 0) unit = unit.setY(1.0); + if (unit.getZ() == 0) unit = unit.setZ(1.0); + } + + try { + final int affected = editSession.makeBiomeShape(region, zero, unit, target, expression, hollow); + player.findFreePosition(); + player.print("Biome changed to " + target.getName() + ". " + affected + " columns affected."); + } catch (ExpressionException e) { + player.printError(e.getMessage()); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/commands/HistoryCommands.java b/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/commands/HistoryCommands.java rename to src/main/java/com/sk89q/worldedit/command/HistoryCommands.java index 03346ac93..930925ae5 100644 --- a/src/main/java/com/sk89q/worldedit/commands/HistoryCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java @@ -1,123 +1,123 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.commands; - -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.worldedit.*; - -/** - * History little commands. - * - * @author sk89q - */ -public class HistoryCommands { - private final WorldEdit we; - - public HistoryCommands(WorldEdit we) { - this.we = we; - } - - @Command( - aliases = { "/undo", "undo" }, - usage = "[times] [player]", - desc = "Undoes the last action", - min = 0, - max = 2 - ) - @CommandPermissions("worldedit.history.undo") - public void undo(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - int times = Math.max(1, args.getInteger(0, 1)); - for (int i = 0; i < times; ++i) { - EditSession undone; - if (args.argsLength() < 2) { - undone = session.undo(session.getBlockBag(player), player); - } else { - player.checkPermission("worldedit.history.undo.other"); - LocalSession sess = we.getSession(args.getString(1)); - if (sess == null) { - player.printError("Unable to find session for " + args.getString(1)); - break; - } - undone = sess.undo(session.getBlockBag(player), player); - } - if (undone != null) { - player.print("Undo successful."); - we.flushBlockBag(player, undone); - } else { - player.printError("Nothing left to undo."); - break; - } - } - } - - @Command( - aliases = { "/redo", "redo" }, - usage = "[times] [player]", - desc = "Redoes the last action (from history)", - min = 0, - max = 2 - ) - @CommandPermissions("worldedit.history.redo") - public void redo(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - int times = Math.max(1, args.getInteger(0, 1)); - - for (int i = 0; i < times; ++i) { - EditSession redone; - if (args.argsLength() < 2) { - redone = session.redo(session.getBlockBag(player), player); - } else { - player.checkPermission("worldedit.history.redo.other"); - LocalSession sess = we.getSession(args.getString(1)); - if (sess == null) { - player.printError("Unable to find session for " + args.getString(1)); - break; - } - redone = sess.redo(session.getBlockBag(player), player); - } - if (redone != null) { - player.print("Redo successful."); - we.flushBlockBag(player, redone); - } else { - player.printError("Nothing left to redo."); - } - } - } - - @Command( - aliases = { "/clearhistory", "clearhistory" }, - usage = "", - desc = "Clear your history", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.history.clear") - public void clearHistory(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - session.clearHistory(); - player.print("History cleared."); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command; + +import com.sk89q.minecraft.util.commands.Command; +import com.sk89q.minecraft.util.commands.CommandContext; +import com.sk89q.minecraft.util.commands.CommandPermissions; +import com.sk89q.worldedit.*; + +/** + * History little commands. + * + * @author sk89q + */ +public class HistoryCommands { + private final WorldEdit we; + + public HistoryCommands(WorldEdit we) { + this.we = we; + } + + @Command( + aliases = { "/undo", "undo" }, + usage = "[times] [player]", + desc = "Undoes the last action", + min = 0, + max = 2 + ) + @CommandPermissions("worldedit.history.undo") + public void undo(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + int times = Math.max(1, args.getInteger(0, 1)); + for (int i = 0; i < times; ++i) { + EditSession undone; + if (args.argsLength() < 2) { + undone = session.undo(session.getBlockBag(player), player); + } else { + player.checkPermission("worldedit.history.undo.other"); + LocalSession sess = we.getSession(args.getString(1)); + if (sess == null) { + player.printError("Unable to find session for " + args.getString(1)); + break; + } + undone = sess.undo(session.getBlockBag(player), player); + } + if (undone != null) { + player.print("Undo successful."); + we.flushBlockBag(player, undone); + } else { + player.printError("Nothing left to undo."); + break; + } + } + } + + @Command( + aliases = { "/redo", "redo" }, + usage = "[times] [player]", + desc = "Redoes the last action (from history)", + min = 0, + max = 2 + ) + @CommandPermissions("worldedit.history.redo") + public void redo(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + int times = Math.max(1, args.getInteger(0, 1)); + + for (int i = 0; i < times; ++i) { + EditSession redone; + if (args.argsLength() < 2) { + redone = session.redo(session.getBlockBag(player), player); + } else { + player.checkPermission("worldedit.history.redo.other"); + LocalSession sess = we.getSession(args.getString(1)); + if (sess == null) { + player.printError("Unable to find session for " + args.getString(1)); + break; + } + redone = sess.redo(session.getBlockBag(player), player); + } + if (redone != null) { + player.print("Redo successful."); + we.flushBlockBag(player, redone); + } else { + player.printError("Nothing left to redo."); + } + } + } + + @Command( + aliases = { "/clearhistory", "clearhistory" }, + usage = "", + desc = "Clear your history", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.history.clear") + public void clearHistory(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + session.clearHistory(); + player.print("History cleared."); + } +} diff --git a/src/main/java/com/sk89q/worldedit/commands/InsufficientArgumentsException.java b/src/main/java/com/sk89q/worldedit/command/InsufficientArgumentsException.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/commands/InsufficientArgumentsException.java rename to src/main/java/com/sk89q/worldedit/command/InsufficientArgumentsException.java index 488f99023..2ebd93790 100644 --- a/src/main/java/com/sk89q/worldedit/commands/InsufficientArgumentsException.java +++ b/src/main/java/com/sk89q/worldedit/command/InsufficientArgumentsException.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.commands; +package com.sk89q.worldedit.command; import com.sk89q.worldedit.WorldEditException; diff --git a/src/main/java/com/sk89q/worldedit/commands/NavigationCommands.java b/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/commands/NavigationCommands.java rename to src/main/java/com/sk89q/worldedit/command/NavigationCommands.java index 17b1df07a..440ba8ef3 100644 --- a/src/main/java/com/sk89q/worldedit/commands/NavigationCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java @@ -1,216 +1,216 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.commands; - -import static com.sk89q.minecraft.util.commands.Logging.LogMode.POSITION; - -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.Logging; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.LocalConfiguration; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.WorldVector; - -/** - * Navigation commands. - * - * @author sk89q - */ -public class NavigationCommands { - @SuppressWarnings("unused") - private final WorldEdit we; - - public NavigationCommands(WorldEdit we) { - this.we = we; - } - - @Command( - aliases = { "unstuck", "!" }, - usage = "", - desc = "Escape from being stuck inside a block", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.navigation.unstuck") - public void unstuck(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - player.print("There you go!"); - player.findFreePosition(); - } - - @Command( - aliases = { "ascend", "asc" }, - usage = "[# of levels]", - desc = "Go up a floor", - min = 0, - max = 1 - ) - @CommandPermissions("worldedit.navigation.ascend") - public void ascend(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - int levelsToAscend = 0; - if (args.argsLength() == 0) { - levelsToAscend = 1; - } else { - levelsToAscend = args.getInteger(0); - } - int ascentLevels = 1; - while (player.ascendLevel() && levelsToAscend != ascentLevels) { - ++ascentLevels; - } - if (ascentLevels == 0) { - player.printError("No free spot above you found."); - } else { - player.print((ascentLevels != 1) ? "Ascended " + Integer.toString(ascentLevels) + " levels." : "Ascended a level."); - } - } - - @Command( - aliases = { "descend", "desc" }, - usage = "[# of floors]", - desc = "Go down a floor", - min = 0, - max = 1 - ) - @CommandPermissions("worldedit.navigation.descend") - public void descend(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - int levelsToDescend = 0; - if (args.argsLength() == 0) { - levelsToDescend = 1; - } else { - levelsToDescend = args.getInteger(0); - } - int descentLevels = 1; - while (player.descendLevel() && levelsToDescend != descentLevels) { - ++descentLevels; - } - if (descentLevels == 0) { - player.printError("No free spot above you found."); - } else { - player.print((descentLevels != 1) ? "Descended " + Integer.toString(descentLevels) + " levels." : "Descended a level."); - } - } - - @Command( - aliases = { "ceil" }, - usage = "[clearance]", - desc = "Go to the celing", - flags = "fg", - min = 0, - max = 1 - ) - @CommandPermissions("worldedit.navigation.ceiling") - @Logging(POSITION) - public void ceiling(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - final int clearance = args.argsLength() > 0 ? - Math.max(0, args.getInteger(0)) : 0; - - final boolean alwaysGlass = getAlwaysGlass(args); - if (player.ascendToCeiling(clearance, alwaysGlass)) { - player.print("Whoosh!"); - } else { - player.printError("No free spot above you found."); - } - } - - @Command( - aliases = { "thru" }, - usage = "", - desc = "Passthrough walls", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.navigation.thru.command") - public void thru(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - if (player.passThroughForwardWall(6)) { - player.print("Whoosh!"); - } else { - player.printError("No free spot ahead of you found."); - } - } - - @Command( - aliases = { "jumpto", "j" }, - usage = "", - desc = "Teleport to a location", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.navigation.jumpto.command") - public void jumpTo(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - WorldVector pos = player.getSolidBlockTrace(300); - if (pos != null) { - player.findFreePosition(pos); - player.print("Poof!"); - } else { - player.printError("No block in sight!"); - } - } - - @Command( - aliases = { "up" }, - usage = "", - desc = "Go upwards some distance", - flags = "fg", - min = 1, - max = 1 - ) - @CommandPermissions("worldedit.navigation.up") - @Logging(POSITION) - public void up(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - final int distance = args.getInteger(0); - - final boolean alwaysGlass = getAlwaysGlass(args); - if (player.ascendUpwards(distance, alwaysGlass)) { - player.print("Whoosh!"); - } else { - player.printError("You would hit something above you."); - } - } - - /** - * Helper function for /up and /ceil. - * - * @param args The {@link CommandContext} to extract the flags from. - * @return true, if glass should always be put under the player - */ - private boolean getAlwaysGlass(CommandContext args) { - final LocalConfiguration config = we.getConfiguration(); - - final boolean forceFlight = args.hasFlag('f'); - final boolean forceGlass = args.hasFlag('g'); - - return forceGlass || (config.navigationUseGlass && !forceFlight); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command; + +import static com.sk89q.minecraft.util.commands.Logging.LogMode.POSITION; + +import com.sk89q.minecraft.util.commands.Command; +import com.sk89q.minecraft.util.commands.CommandContext; +import com.sk89q.minecraft.util.commands.CommandPermissions; +import com.sk89q.minecraft.util.commands.Logging; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.WorldVector; + +/** + * Navigation commands. + * + * @author sk89q + */ +public class NavigationCommands { + @SuppressWarnings("unused") + private final WorldEdit we; + + public NavigationCommands(WorldEdit we) { + this.we = we; + } + + @Command( + aliases = { "unstuck", "!" }, + usage = "", + desc = "Escape from being stuck inside a block", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.navigation.unstuck") + public void unstuck(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + player.print("There you go!"); + player.findFreePosition(); + } + + @Command( + aliases = { "ascend", "asc" }, + usage = "[# of levels]", + desc = "Go up a floor", + min = 0, + max = 1 + ) + @CommandPermissions("worldedit.navigation.ascend") + public void ascend(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + int levelsToAscend = 0; + if (args.argsLength() == 0) { + levelsToAscend = 1; + } else { + levelsToAscend = args.getInteger(0); + } + int ascentLevels = 1; + while (player.ascendLevel() && levelsToAscend != ascentLevels) { + ++ascentLevels; + } + if (ascentLevels == 0) { + player.printError("No free spot above you found."); + } else { + player.print((ascentLevels != 1) ? "Ascended " + Integer.toString(ascentLevels) + " levels." : "Ascended a level."); + } + } + + @Command( + aliases = { "descend", "desc" }, + usage = "[# of floors]", + desc = "Go down a floor", + min = 0, + max = 1 + ) + @CommandPermissions("worldedit.navigation.descend") + public void descend(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + int levelsToDescend = 0; + if (args.argsLength() == 0) { + levelsToDescend = 1; + } else { + levelsToDescend = args.getInteger(0); + } + int descentLevels = 1; + while (player.descendLevel() && levelsToDescend != descentLevels) { + ++descentLevels; + } + if (descentLevels == 0) { + player.printError("No free spot above you found."); + } else { + player.print((descentLevels != 1) ? "Descended " + Integer.toString(descentLevels) + " levels." : "Descended a level."); + } + } + + @Command( + aliases = { "ceil" }, + usage = "[clearance]", + desc = "Go to the celing", + flags = "fg", + min = 0, + max = 1 + ) + @CommandPermissions("worldedit.navigation.ceiling") + @Logging(POSITION) + public void ceiling(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + final int clearance = args.argsLength() > 0 ? + Math.max(0, args.getInteger(0)) : 0; + + final boolean alwaysGlass = getAlwaysGlass(args); + if (player.ascendToCeiling(clearance, alwaysGlass)) { + player.print("Whoosh!"); + } else { + player.printError("No free spot above you found."); + } + } + + @Command( + aliases = { "thru" }, + usage = "", + desc = "Passthrough walls", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.navigation.thru.command") + public void thru(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + if (player.passThroughForwardWall(6)) { + player.print("Whoosh!"); + } else { + player.printError("No free spot ahead of you found."); + } + } + + @Command( + aliases = { "jumpto", "j" }, + usage = "", + desc = "Teleport to a location", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.navigation.jumpto.command") + public void jumpTo(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + WorldVector pos = player.getSolidBlockTrace(300); + if (pos != null) { + player.findFreePosition(pos); + player.print("Poof!"); + } else { + player.printError("No block in sight!"); + } + } + + @Command( + aliases = { "up" }, + usage = "", + desc = "Go upwards some distance", + flags = "fg", + min = 1, + max = 1 + ) + @CommandPermissions("worldedit.navigation.up") + @Logging(POSITION) + public void up(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + final int distance = args.getInteger(0); + + final boolean alwaysGlass = getAlwaysGlass(args); + if (player.ascendUpwards(distance, alwaysGlass)) { + player.print("Whoosh!"); + } else { + player.printError("You would hit something above you."); + } + } + + /** + * Helper function for /up and /ceil. + * + * @param args The {@link CommandContext} to extract the flags from. + * @return true, if glass should always be put under the player + */ + private boolean getAlwaysGlass(CommandContext args) { + final LocalConfiguration config = we.getConfiguration(); + + final boolean forceFlight = args.hasFlag('f'); + final boolean forceGlass = args.hasFlag('g'); + + return forceGlass || (config.navigationUseGlass && !forceFlight); + } +} diff --git a/src/main/java/com/sk89q/worldedit/commands/RegionCommands.java b/src/main/java/com/sk89q/worldedit/command/RegionCommands.java similarity index 91% rename from src/main/java/com/sk89q/worldedit/commands/RegionCommands.java rename to src/main/java/com/sk89q/worldedit/command/RegionCommands.java index be7725879..ccaa0bf60 100644 --- a/src/main/java/com/sk89q/worldedit/commands/RegionCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -1,590 +1,585 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.commands; - -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.Logging; -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.blocks.BlockID; -import com.sk89q.worldedit.expression.ExpressionException; -import com.sk89q.worldedit.filtering.GaussianKernel; -import com.sk89q.worldedit.filtering.HeightMapFilter; -import com.sk89q.worldedit.generator.FloraGenerator; -import com.sk89q.worldedit.generator.ForestGenerator; -import com.sk89q.worldedit.operation.GroundScatterFunction; -import com.sk89q.worldedit.masks.Mask; -import com.sk89q.worldedit.operation.FlatRegionApplicator; -import com.sk89q.worldedit.operation.OperationHelper; -import com.sk89q.worldedit.patterns.Pattern; -import com.sk89q.worldedit.patterns.SingleBlockPattern; -import com.sk89q.worldedit.regions.*; -import com.sk89q.worldedit.util.TreeGenerator; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -import static com.sk89q.minecraft.util.commands.Logging.LogMode.*; - -/** - * Region related commands. - * - * @author sk89q - */ -public class RegionCommands { - private final WorldEdit we; - - public RegionCommands(WorldEdit we) { - this.we = we; - } - - @Command( - aliases = { "/set" }, - usage = "", - desc = "Set all the blocks inside the selection to a block", - min = 1, - max = 1 - ) - @CommandPermissions("worldedit.region.set") - @Logging(REGION) - public void set(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - Pattern pattern = we.getBlockPattern(player, args.getString(0)); - - int affected; - - if (pattern instanceof SingleBlockPattern) { - affected = editSession.setBlocks(session.getSelection(player.getWorld()), - ((SingleBlockPattern) pattern).getBlock()); - } else { - affected = editSession.setBlocks(session.getSelection(player.getWorld()), pattern); - } - - player.print(affected + " block(s) have been changed."); - } - - @Command( - aliases = { "/line" }, - usage = " [thickness]", - desc = "Draws a line segment between cuboid selection corners", - help = - "Draws a line segment between cuboid selection corners.\n" + - "Can only be used with cuboid selections.\n" + - "Flags:\n" + - " -h generates only a shell", - flags = "h", - min = 1, - max = 2 - ) - @CommandPermissions("worldedit.region.line") - @Logging(REGION) - public void line(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - Region region = session.getSelection(session.getSelectionWorld()); - if (!(region instanceof CuboidRegion)) { - player.printError("Invalid region type"); - return; - } - if (args.argsLength() < 2 ? false : args.getDouble(1) < 0) { - player.printError("Invalid thickness. Must not be negative"); - return; - } - - Pattern pattern = we.getBlockPattern(player, args.getString(0)); - CuboidRegion cuboidregion = (CuboidRegion) region; - Vector pos1 = cuboidregion.getPos1(); - Vector pos2 = cuboidregion.getPos2(); - int blocksChanged = editSession.drawLine(pattern, pos1, pos2, args.argsLength() < 2 ? 0 : args.getDouble(1), !args.hasFlag('h')); - - player.print(blocksChanged + " block(s) have been changed."); - } - - @Command( - aliases = { "/curve" }, - usage = " [thickness]", - desc = "Draws a spline through selected points", - help = - "Draws a spline through selected points.\n" + - "Can only be uesd with convex polyhedral selections.\n" + - "Flags:\n" + - " -h generates only a shell", - flags = "h", - min = 1, - max = 2 - ) - @CommandPermissions("worldedit.region.curve") - @Logging(REGION) - public void curve(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - Region region = session.getSelection(session.getSelectionWorld()); - if (!(region instanceof ConvexPolyhedralRegion)) { - player.printError("Invalid region type"); - return; - } - if (args.argsLength() < 2 ? false : args.getDouble(1) < 0) { - player.printError("Invalid thickness. Must not be negative"); - return; - } - - Pattern pattern = we.getBlockPattern(player, args.getString(0)); - ConvexPolyhedralRegion cpregion = (ConvexPolyhedralRegion) region; - List vectors = new ArrayList(cpregion.getVertices()); - - int blocksChanged = editSession.drawSpline(pattern, vectors, 0, 0, 0, 10, args.argsLength() < 2 ? 0 : args.getDouble(1), !args.hasFlag('h')); - - player.print(blocksChanged + " block(s) have been changed."); - } - - @Command( - aliases = { "/replace", "/re", "/rep" }, - usage = "[from-block] ", - desc = "Replace all blocks in the selection with another", - flags = "f", - min = 1, - max = 2 - ) - @CommandPermissions("worldedit.region.replace") - @Logging(REGION) - public void replace(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - Set from; - Pattern to; - if (args.argsLength() == 1) { - from = null; - to = we.getBlockPattern(player, args.getString(0)); - } else { - from = we.getBlocks(player, args.getString(0), true, !args.hasFlag('f')); - to = we.getBlockPattern(player, args.getString(1)); - } - - final int affected; - if (to instanceof SingleBlockPattern) { - affected = editSession.replaceBlocks(session.getSelection(player.getWorld()), from, - ((SingleBlockPattern) to).getBlock()); - } else { - affected = editSession.replaceBlocks(session.getSelection(player.getWorld()), from, to); - } - - player.print(affected + " block(s) have been replaced."); - } - - @Command( - aliases = { "/overlay" }, - usage = "", - desc = "Set a block on top of blocks in the region", - min = 1, - max = 1 - ) - @CommandPermissions("worldedit.region.overlay") - @Logging(REGION) - public void overlay(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - Pattern pat = we.getBlockPattern(player, args.getString(0)); - - Region region = session.getSelection(player.getWorld()); - int affected = 0; - if (pat instanceof SingleBlockPattern) { - affected = editSession.overlayCuboidBlocks(region, - ((SingleBlockPattern) pat).getBlock()); - } else { - affected = editSession.overlayCuboidBlocks(region, pat); - } - player.print(affected + " block(s) have been overlayed."); - } - - @Command( - aliases = { "/center", "/middle" }, - usage = "", - desc = "Set the center block(s)", - min = 1, - max = 1 - ) - @Logging(REGION) - @CommandPermissions("worldedit.region.center") - public void center(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - Pattern pattern = we.getBlockPattern(player, args.getString(0)); - Region region = session.getSelection(player.getWorld()); - - int affected = editSession.center(region, pattern); - player.print("Center set ("+ affected + " blocks changed)"); - } - - @Command( - aliases = { "/naturalize" }, - usage = "", - desc = "3 layers of dirt on top then rock below", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.region.naturalize") - @Logging(REGION) - public void naturalize(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - Region region = session.getSelection(player.getWorld()); - int affected = editSession.naturalizeCuboidBlocks(region); - player.print(affected + " block(s) have been naturalized."); - } - - @Command( - aliases = { "/walls" }, - usage = "", - desc = "Build the four sides of the selection", - min = 1, - max = 1 - ) - @CommandPermissions("worldedit.region.walls") - @Logging(REGION) - public void walls(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - final Pattern pattern = we.getBlockPattern(player, args.getString(0)); - final int affected; - final Region region = session.getSelection(player.getWorld()); - if (!(region instanceof CuboidRegion)) { - affected = editSession.makeWalls(region, pattern); - } else if (pattern instanceof SingleBlockPattern) { - affected = editSession.makeCuboidWalls(region, ((SingleBlockPattern) pattern).getBlock()); - } else { - affected = editSession.makeCuboidWalls(region, pattern); - } - - player.print(affected + " block(s) have been changed."); - } - - @Command( - aliases = { "/faces", "/outline" }, - usage = "", - desc = "Build the walls, ceiling, and floor of a selection", - min = 1, - max = 1 - ) - @CommandPermissions("worldedit.region.faces") - @Logging(REGION) - public void faces(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - final Pattern pattern = we.getBlockPattern(player, args.getString(0)); - final int affected; - final Region region = session.getSelection(player.getWorld()); - if (!(region instanceof CuboidRegion)) { - affected = editSession.makeFaces(region, pattern); - } else if (pattern instanceof SingleBlockPattern) { - affected = editSession.makeCuboidFaces(region, ((SingleBlockPattern) pattern).getBlock()); - } else { - affected = editSession.makeCuboidFaces(region, pattern); - } - - player.print(affected + " block(s) have been changed."); - } - - @Command( - aliases = { "/smooth" }, - usage = "[iterations]", - flags = "n", - desc = "Smooth the elevation in the selection", - help = - "Smooths the elevation in the selection.\n" + - "The -n flag makes it only consider naturally occuring blocks.", - min = 0, - max = 1 - ) - @CommandPermissions("worldedit.region.smooth") - @Logging(REGION) - public void smooth(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - int iterations = 1; - if (args.argsLength() > 0) { - iterations = args.getInteger(0); - } - - HeightMap heightMap = new HeightMap(editSession, session.getSelection(player.getWorld()), args.hasFlag('n')); - HeightMapFilter filter = new HeightMapFilter(new GaussianKernel(5, 1.0)); - int affected = heightMap.applyFilter(filter, iterations); - player.print("Terrain's height map smoothed. " + affected + " block(s) changed."); - - } - - @Command( - aliases = { "/move" }, - usage = "[count] [direction] [leave-id]", - flags = "s", - desc = "Move the contents of the selection", - help = - "Moves the contents of the selection.\n" + - "The -s flag shifts the selection to the target location.\n" + - "Optionally fills the old location with .", - min = 0, - max = 3 - ) - @CommandPermissions("worldedit.region.move") - @Logging(ORIENTATION_REGION) - public void move(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - int count = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 1; - Vector dir = we.getDirection(player, - args.argsLength() > 1 ? args.getString(1).toLowerCase() : "me"); - BaseBlock replace; - - // Replacement block argument - if (args.argsLength() > 2) { - replace = we.getBlock(player, args.getString(2)); - } else { - replace = new BaseBlock(BlockID.AIR); - } - - int affected = editSession.moveRegion(session.getSelection(player.getWorld()), - dir, count, true, replace); - - if (args.hasFlag('s')) { - try { - Region region = session.getSelection(player.getWorld()); - region.shift(dir.multiply(count)); - - session.getRegionSelector(player.getWorld()).learnChanges(); - session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); - } catch (RegionOperationException e) { - player.printError(e.getMessage()); - } - } - - player.print(affected + " blocks moved."); - } - - @Command( - aliases = { "/stack" }, - usage = "[count] [direction]", - flags = "sa", - desc = "Repeat the contents of the selection", - help = - "Repeats the contents of the selection.\n" + - "Flags:\n" + - " -s shifts the selection to the last stacked copy\n" + - " -a skips air blocks", - min = 0, - max = 2 - ) - @CommandPermissions("worldedit.region.stack") - @Logging(ORIENTATION_REGION) - public void stack(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - int count = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 1; - Vector dir = we.getDiagonalDirection(player, - args.argsLength() > 1 ? args.getString(1).toLowerCase() : "me"); - - int affected = editSession.stackCuboidRegion(session.getSelection(player.getWorld()), - dir, count, !args.hasFlag('a')); - - if (args.hasFlag('s')) { - try { - final Region region = session.getSelection(player.getWorld()); - final Vector size = region.getMaximumPoint().subtract(region.getMinimumPoint()); - - final Vector shiftVector = dir.multiply(count * (Math.abs(dir.dot(size)) + 1)); - region.shift(shiftVector); - - session.getRegionSelector(player.getWorld()).learnChanges(); - session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); - } catch (RegionOperationException e) { - player.printError(e.getMessage()); - } - } - - player.print(affected + " blocks changed. Undo with //undo"); - } - - @Command( - aliases = { "/regen" }, - usage = "", - desc = "Regenerates the contents of the selection", - help = - "Regenerates the contents of the current selection.\n" + - "This command might affect things outside the selection,\n" + - "if they are within the same chunk.", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.regen") - @Logging(REGION) - public void regenerateChunk(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - Region region = session.getSelection(player.getWorld()); - Mask mask = session.getMask(); - session.setMask(null); - player.getWorld().regenerate(region, editSession); - session.setMask(mask); - player.print("Region regenerated."); - } - - @Command( - aliases = { "/deform" }, - usage = "", - desc = "Deforms a selected region with an expression", - help = - "Deforms a selected region with an expression\n" + - "The expression is executed for each block and is expected\n" + - "to modify the variables x, y and z to point to a new block\n" + - "to fetch. See also tinyurl.com/wesyntax.", - flags = "ro", - min = 1, - max = -1 - ) - @CommandPermissions("worldedit.region.deform") - @Logging(ALL) - public void deform(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - final Region region = session.getSelection(player.getWorld()); - - final String expression = args.getJoinedStrings(0); - - final Vector zero; - Vector unit; - - if (args.hasFlag('r')) { - zero = Vector.ZERO; - unit = Vector.ONE; - } else if (args.hasFlag('o')) { - zero = session.getPlacementPosition(player); - unit = Vector.ONE; - } else { - final Vector min = region.getMinimumPoint(); - final Vector max = region.getMaximumPoint(); - - zero = max.add(min).multiply(0.5); - unit = max.subtract(zero); - - if (unit.getX() == 0) unit = unit.setX(1.0); - if (unit.getY() == 0) unit = unit.setY(1.0); - if (unit.getZ() == 0) unit = unit.setZ(1.0); - } - - try { - final int affected = editSession.deformRegion(region, zero, unit, expression); - player.findFreePosition(); - player.print(affected + " block(s) have been deformed."); - } catch (ExpressionException e) { - player.printError(e.getMessage()); - } - } - - @Command( - aliases = { "/hollow" }, - usage = "[[ ]]", - desc = "Hollows out the object contained in this selection", - help = - "Hollows out the object contained in this selection.\n" + - "Optionally fills the hollowed out part with the given block.\n" + - "Thickness is measured in manhattan distance.", - min = 0, - max = 2 - ) - @CommandPermissions("worldedit.region.hollow") - @Logging(REGION) - public void hollow(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - final int thickness = args.argsLength() >= 1 ? Math.max(1, args.getInteger(0)) : 1; - final Pattern pattern = args.argsLength() >= 2 ? we.getBlockPattern(player, args.getString(1)) : new SingleBlockPattern(new BaseBlock(BlockID.AIR)); - - final int affected = editSession.hollowOutRegion(session.getSelection(player.getWorld()), thickness, pattern); - - player.print(affected + " block(s) have been changed."); - } - - @Command( - aliases = { "/forest" }, - usage = "[type] [density]", - desc = "Make a forest within the region", - min = 0, - max = 2 - ) - @CommandPermissions("worldedit.region.forest") - @Logging(REGION) - public void forest(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - TreeGenerator.TreeType type = args.argsLength() > 0 ? TreeGenerator.lookup(args.getString(0)) : TreeGenerator.TreeType.TREE; - double density = args.argsLength() > 1 ? args.getDouble(1) / 100 : 0.05; - - if (type == null) { - player.printError("Tree type '" + args.getString(0) + "' is unknown."); - return; - } - - Region region = session.getSelection(player.getWorld()); - - // We want to generate trees - ForestGenerator generator = new ForestGenerator(editSession, new TreeGenerator(type)); - - // And we want to scatter them - GroundScatterFunction scatter = new GroundScatterFunction(editSession, generator); - scatter.setDensity(density); - scatter.setRange(region); - - // Generate that forest - FlatRegionApplicator operation = new FlatRegionApplicator(region, scatter); - OperationHelper.complete(operation); - - player.print(operation.getAffected() + " trees created."); - } - - @Command( - aliases = { "/flora" }, - usage = "[density]", - desc = "Make flora within the region", - min = 0, - max = 1 - ) - @CommandPermissions("worldedit.region.flora") - @Logging(REGION) - public void flora(CommandContext args, LocalSession session, LocalPlayer player, EditSession editSession) throws WorldEditException { - double density = args.argsLength() > 0 ? args.getDouble(0) / 100 : 0.1; - - Region region = session.getSelection(player.getWorld()); - - // We want to generate flora - FloraGenerator generator = new FloraGenerator(editSession); - - // And we want to scatter them - GroundScatterFunction scatter = new GroundScatterFunction(editSession, generator); - scatter.setDensity(density); - scatter.setRange(region); - - // Generate that flora - FlatRegionApplicator operation = new FlatRegionApplicator(region, scatter); - OperationHelper.complete(operation); - - player.print(operation.getAffected() + " flora created."); - } - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command; + +import com.sk89q.minecraft.util.commands.Command; +import com.sk89q.minecraft.util.commands.CommandContext; +import com.sk89q.minecraft.util.commands.CommandPermissions; +import com.sk89q.minecraft.util.commands.Logging; +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockID; +import com.sk89q.worldedit.internal.expression.ExpressionException; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.math.convolution.GaussianKernel; +import com.sk89q.worldedit.math.convolution.HeightMap; +import com.sk89q.worldedit.math.convolution.HeightMapFilter; +import com.sk89q.worldedit.function.GroundFunction; +import com.sk89q.worldedit.function.generator.FloraGenerator; +import com.sk89q.worldedit.function.generator.ForestGenerator; +import com.sk89q.worldedit.function.visitor.LayerVisitor; +import com.sk89q.worldedit.masks.Mask; +import com.sk89q.worldedit.function.mask.NoiseFilter2D; +import com.sk89q.worldedit.patterns.Pattern; +import com.sk89q.worldedit.patterns.SingleBlockPattern; +import com.sk89q.worldedit.regions.ConvexPolyhedralRegion; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionOperationException; +import com.sk89q.worldedit.util.TreeGenerator; +import com.sk89q.worldedit.math.noise.RandomNoise; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import static com.sk89q.minecraft.util.commands.Logging.LogMode.*; +import static com.sk89q.worldedit.regions.Regions.*; + +/** + * Region related commands. + * + * @author sk89q + */ +public class RegionCommands { + private final WorldEdit we; + + public RegionCommands(WorldEdit we) { + this.we = we; + } + + @Command( + aliases = { "/set" }, + usage = "", + desc = "Set all the blocks inside the selection to a block", + min = 1, + max = 1 + ) + @CommandPermissions("worldedit.region.set") + @Logging(REGION) + public void set(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + Pattern pattern = we.getBlockPattern(player, args.getString(0)); + + int affected; + + if (pattern instanceof SingleBlockPattern) { + affected = editSession.setBlocks(session.getSelection(player.getWorld()), + ((SingleBlockPattern) pattern).getBlock()); + } else { + affected = editSession.setBlocks(session.getSelection(player.getWorld()), pattern); + } + + player.print(affected + " block(s) have been changed."); + } + + @Command( + aliases = { "/line" }, + usage = " [thickness]", + desc = "Draws a line segment between cuboid selection corners", + help = + "Draws a line segment between cuboid selection corners.\n" + + "Can only be used with cuboid selections.\n" + + "Flags:\n" + + " -h generates only a shell", + flags = "h", + min = 1, + max = 2 + ) + @CommandPermissions("worldedit.region.line") + @Logging(REGION) + public void line(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + Region region = session.getSelection(session.getSelectionWorld()); + if (!(region instanceof CuboidRegion)) { + player.printError("Invalid region type"); + return; + } + if (args.argsLength() < 2 ? false : args.getDouble(1) < 0) { + player.printError("Invalid thickness. Must not be negative"); + return; + } + + Pattern pattern = we.getBlockPattern(player, args.getString(0)); + CuboidRegion cuboidregion = (CuboidRegion) region; + Vector pos1 = cuboidregion.getPos1(); + Vector pos2 = cuboidregion.getPos2(); + int blocksChanged = editSession.drawLine(pattern, pos1, pos2, args.argsLength() < 2 ? 0 : args.getDouble(1), !args.hasFlag('h')); + + player.print(blocksChanged + " block(s) have been changed."); + } + + @Command( + aliases = { "/curve" }, + usage = " [thickness]", + desc = "Draws a spline through selected points", + help = + "Draws a spline through selected points.\n" + + "Can only be uesd with convex polyhedral selections.\n" + + "Flags:\n" + + " -h generates only a shell", + flags = "h", + min = 1, + max = 2 + ) + @CommandPermissions("worldedit.region.curve") + @Logging(REGION) + public void curve(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + Region region = session.getSelection(session.getSelectionWorld()); + if (!(region instanceof ConvexPolyhedralRegion)) { + player.printError("Invalid region type"); + return; + } + if (args.argsLength() < 2 ? false : args.getDouble(1) < 0) { + player.printError("Invalid thickness. Must not be negative"); + return; + } + + Pattern pattern = we.getBlockPattern(player, args.getString(0)); + ConvexPolyhedralRegion cpregion = (ConvexPolyhedralRegion) region; + List vectors = new ArrayList(cpregion.getVertices()); + + int blocksChanged = editSession.drawSpline(pattern, vectors, 0, 0, 0, 10, args.argsLength() < 2 ? 0 : args.getDouble(1), !args.hasFlag('h')); + + player.print(blocksChanged + " block(s) have been changed."); + } + + @Command( + aliases = { "/replace", "/re", "/rep" }, + usage = "[from-block] ", + desc = "Replace all blocks in the selection with another", + flags = "f", + min = 1, + max = 2 + ) + @CommandPermissions("worldedit.region.replace") + @Logging(REGION) + public void replace(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + Set from; + Pattern to; + if (args.argsLength() == 1) { + from = null; + to = we.getBlockPattern(player, args.getString(0)); + } else { + from = we.getBlocks(player, args.getString(0), true, !args.hasFlag('f')); + to = we.getBlockPattern(player, args.getString(1)); + } + + final int affected; + if (to instanceof SingleBlockPattern) { + affected = editSession.replaceBlocks(session.getSelection(player.getWorld()), from, + ((SingleBlockPattern) to).getBlock()); + } else { + affected = editSession.replaceBlocks(session.getSelection(player.getWorld()), from, to); + } + + player.print(affected + " block(s) have been replaced."); + } + + @Command( + aliases = { "/overlay" }, + usage = "", + desc = "Set a block on top of blocks in the region", + min = 1, + max = 1 + ) + @CommandPermissions("worldedit.region.overlay") + @Logging(REGION) + public void overlay(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + Pattern pat = we.getBlockPattern(player, args.getString(0)); + + Region region = session.getSelection(player.getWorld()); + int affected = 0; + if (pat instanceof SingleBlockPattern) { + affected = editSession.overlayCuboidBlocks(region, + ((SingleBlockPattern) pat).getBlock()); + } else { + affected = editSession.overlayCuboidBlocks(region, pat); + } + player.print(affected + " block(s) have been overlayed."); + } + + @Command( + aliases = { "/center", "/middle" }, + usage = "", + desc = "Set the center block(s)", + min = 1, + max = 1 + ) + @Logging(REGION) + @CommandPermissions("worldedit.region.center") + public void center(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + Pattern pattern = we.getBlockPattern(player, args.getString(0)); + Region region = session.getSelection(player.getWorld()); + + int affected = editSession.center(region, pattern); + player.print("Center set ("+ affected + " blocks changed)"); + } + + @Command( + aliases = { "/naturalize" }, + usage = "", + desc = "3 layers of dirt on top then rock below", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.region.naturalize") + @Logging(REGION) + public void naturalize(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + Region region = session.getSelection(player.getWorld()); + int affected = editSession.naturalizeCuboidBlocks(region); + player.print(affected + " block(s) have been naturalized."); + } + + @Command( + aliases = { "/walls" }, + usage = "", + desc = "Build the four sides of the selection", + min = 1, + max = 1 + ) + @CommandPermissions("worldedit.region.walls") + @Logging(REGION) + public void walls(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + final Pattern pattern = we.getBlockPattern(player, args.getString(0)); + final int affected; + final Region region = session.getSelection(player.getWorld()); + if (!(region instanceof CuboidRegion)) { + affected = editSession.makeWalls(region, pattern); + } else if (pattern instanceof SingleBlockPattern) { + affected = editSession.makeCuboidWalls(region, ((SingleBlockPattern) pattern).getBlock()); + } else { + affected = editSession.makeCuboidWalls(region, pattern); + } + + player.print(affected + " block(s) have been changed."); + } + + @Command( + aliases = { "/faces", "/outline" }, + usage = "", + desc = "Build the walls, ceiling, and floor of a selection", + min = 1, + max = 1 + ) + @CommandPermissions("worldedit.region.faces") + @Logging(REGION) + public void faces(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + final Pattern pattern = we.getBlockPattern(player, args.getString(0)); + final int affected; + final Region region = session.getSelection(player.getWorld()); + if (!(region instanceof CuboidRegion)) { + affected = editSession.makeFaces(region, pattern); + } else if (pattern instanceof SingleBlockPattern) { + affected = editSession.makeCuboidFaces(region, ((SingleBlockPattern) pattern).getBlock()); + } else { + affected = editSession.makeCuboidFaces(region, pattern); + } + + player.print(affected + " block(s) have been changed."); + } + + @Command( + aliases = { "/smooth" }, + usage = "[iterations]", + flags = "n", + desc = "Smooth the elevation in the selection", + help = + "Smooths the elevation in the selection.\n" + + "The -n flag makes it only consider naturally occuring blocks.", + min = 0, + max = 1 + ) + @CommandPermissions("worldedit.region.smooth") + @Logging(REGION) + public void smooth(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + int iterations = 1; + if (args.argsLength() > 0) { + iterations = args.getInteger(0); + } + + HeightMap heightMap = new HeightMap(editSession, session.getSelection(player.getWorld()), args.hasFlag('n')); + HeightMapFilter filter = new HeightMapFilter(new GaussianKernel(5, 1.0)); + int affected = heightMap.applyFilter(filter, iterations); + player.print("Terrain's height map smoothed. " + affected + " block(s) changed."); + + } + + @Command( + aliases = { "/move" }, + usage = "[count] [direction] [leave-id]", + flags = "s", + desc = "Move the contents of the selection", + help = + "Moves the contents of the selection.\n" + + "The -s flag shifts the selection to the target location.\n" + + "Optionally fills the old location with .", + min = 0, + max = 3 + ) + @CommandPermissions("worldedit.region.move") + @Logging(ORIENTATION_REGION) + public void move(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + int count = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 1; + Vector dir = we.getDirection(player, + args.argsLength() > 1 ? args.getString(1).toLowerCase() : "me"); + BaseBlock replace; + + // Replacement block argument + if (args.argsLength() > 2) { + replace = we.getBlock(player, args.getString(2)); + } else { + replace = new BaseBlock(BlockID.AIR); + } + + int affected = editSession.moveRegion(session.getSelection(player.getWorld()), + dir, count, true, replace); + + if (args.hasFlag('s')) { + try { + Region region = session.getSelection(player.getWorld()); + region.shift(dir.multiply(count)); + + session.getRegionSelector(player.getWorld()).learnChanges(); + session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); + } catch (RegionOperationException e) { + player.printError(e.getMessage()); + } + } + + player.print(affected + " blocks moved."); + } + + @Command( + aliases = { "/stack" }, + usage = "[count] [direction]", + flags = "sa", + desc = "Repeat the contents of the selection", + help = + "Repeats the contents of the selection.\n" + + "Flags:\n" + + " -s shifts the selection to the last stacked copy\n" + + " -a skips air blocks", + min = 0, + max = 2 + ) + @CommandPermissions("worldedit.region.stack") + @Logging(ORIENTATION_REGION) + public void stack(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + int count = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 1; + Vector dir = we.getDiagonalDirection(player, + args.argsLength() > 1 ? args.getString(1).toLowerCase() : "me"); + + int affected = editSession.stackCuboidRegion(session.getSelection(player.getWorld()), + dir, count, !args.hasFlag('a')); + + if (args.hasFlag('s')) { + try { + final Region region = session.getSelection(player.getWorld()); + final Vector size = region.getMaximumPoint().subtract(region.getMinimumPoint()); + + final Vector shiftVector = dir.multiply(count * (Math.abs(dir.dot(size)) + 1)); + region.shift(shiftVector); + + session.getRegionSelector(player.getWorld()).learnChanges(); + session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); + } catch (RegionOperationException e) { + player.printError(e.getMessage()); + } + } + + player.print(affected + " blocks changed. Undo with //undo"); + } + + @Command( + aliases = { "/regen" }, + usage = "", + desc = "Regenerates the contents of the selection", + help = + "Regenerates the contents of the current selection.\n" + + "This command might affect things outside the selection,\n" + + "if they are within the same chunk.", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.regen") + @Logging(REGION) + public void regenerateChunk(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + Region region = session.getSelection(player.getWorld()); + Mask mask = session.getMask(); + session.setMask(null); + player.getWorld().regenerate(region, editSession); + session.setMask(mask); + player.print("Region regenerated."); + } + + @Command( + aliases = { "/deform" }, + usage = "", + desc = "Deforms a selected region with an expression", + help = + "Deforms a selected region with an expression\n" + + "The expression is executed for each block and is expected\n" + + "to modify the variables x, y and z to point to a new block\n" + + "to fetch. See also tinyurl.com/wesyntax.", + flags = "ro", + min = 1, + max = -1 + ) + @CommandPermissions("worldedit.region.deform") + @Logging(ALL) + public void deform(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + final Region region = session.getSelection(player.getWorld()); + + final String expression = args.getJoinedStrings(0); + + final Vector zero; + Vector unit; + + if (args.hasFlag('r')) { + zero = Vector.ZERO; + unit = Vector.ONE; + } else if (args.hasFlag('o')) { + zero = session.getPlacementPosition(player); + unit = Vector.ONE; + } else { + final Vector min = region.getMinimumPoint(); + final Vector max = region.getMaximumPoint(); + + zero = max.add(min).multiply(0.5); + unit = max.subtract(zero); + + if (unit.getX() == 0) unit = unit.setX(1.0); + if (unit.getY() == 0) unit = unit.setY(1.0); + if (unit.getZ() == 0) unit = unit.setZ(1.0); + } + + try { + final int affected = editSession.deformRegion(region, zero, unit, expression); + player.findFreePosition(); + player.print(affected + " block(s) have been deformed."); + } catch (ExpressionException e) { + player.printError(e.getMessage()); + } + } + + @Command( + aliases = { "/hollow" }, + usage = "[[ ]]", + desc = "Hollows out the object contained in this selection", + help = + "Hollows out the object contained in this selection.\n" + + "Optionally fills the hollowed out part with the given block.\n" + + "Thickness is measured in manhattan distance.", + min = 0, + max = 2 + ) + @CommandPermissions("worldedit.region.hollow") + @Logging(REGION) + public void hollow(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + final int thickness = args.argsLength() >= 1 ? Math.max(1, args.getInteger(0)) : 1; + final Pattern pattern = args.argsLength() >= 2 ? we.getBlockPattern(player, args.getString(1)) : new SingleBlockPattern(new BaseBlock(BlockID.AIR)); + + final int affected = editSession.hollowOutRegion(session.getSelection(player.getWorld()), thickness, pattern); + + player.print(affected + " block(s) have been changed."); + } + + @Command( + aliases = { "/forest" }, + usage = "[type] [density]", + desc = "Make a forest within the region", + min = 0, + max = 2 + ) + @CommandPermissions("worldedit.region.forest") + @Logging(REGION) + public void forest(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + TreeGenerator.TreeType type = args.argsLength() > 0 ? TreeGenerator.lookup(args.getString(0)) : TreeGenerator.TreeType.TREE; + double density = args.argsLength() > 1 ? args.getDouble(1) / 100 : 0.05; + + if (type == null) { + player.printError("Tree type '" + args.getString(0) + "' is unknown."); + return; + } + + Region region = session.getSelection(player.getWorld()); + + ForestGenerator generator = new ForestGenerator(editSession, new TreeGenerator(type)); + GroundFunction ground = new GroundFunction(new ExistingBlockMask(editSession), generator); + LayerVisitor visitor = new LayerVisitor(asFlatRegion(region), minimumBlockY(region), maximumBlockY(region), ground); + visitor.setMask(new NoiseFilter2D(new RandomNoise(), density)); + Operations.completeLegacy(visitor); + + player.print(ground.getAffected() + " trees created."); + } + + @Command( + aliases = { "/flora" }, + usage = "[density]", + desc = "Make flora within the region", + min = 0, + max = 1 + ) + @CommandPermissions("worldedit.region.flora") + @Logging(REGION) + public void flora(CommandContext args, LocalSession session, LocalPlayer player, EditSession editSession) throws WorldEditException { + double density = args.argsLength() > 0 ? args.getDouble(0) / 100 : 0.1; + + Region region = session.getSelection(player.getWorld()); + FloraGenerator generator = new FloraGenerator(editSession); + GroundFunction ground = new GroundFunction(new ExistingBlockMask(editSession), generator); + LayerVisitor visitor = new LayerVisitor(asFlatRegion(region), minimumBlockY(region), maximumBlockY(region), ground); + visitor.setMask(new NoiseFilter2D(new RandomNoise(), density)); + Operations.completeLegacy(visitor); + + player.print(ground.getAffected() + " flora created."); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/commands/SchematicCommands.java b/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java similarity index 98% rename from src/main/java/com/sk89q/worldedit/commands/SchematicCommands.java rename to src/main/java/com/sk89q/worldedit/command/SchematicCommands.java index 8c5114273..7c768cc81 100644 --- a/src/main/java/com/sk89q/worldedit/commands/SchematicCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.commands; +package com.sk89q.worldedit.command; import java.io.File; import java.io.IOException; @@ -35,13 +35,13 @@ import com.sk89q.worldedit.LocalPlayer; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.data.DataException; +import com.sk89q.worldedit.world.DataException; import com.sk89q.worldedit.schematic.SchematicFormat; /** * Commands related to schematics * - * @see com.sk89q.worldedit.commands.ClipboardCommands#schematic() + * @see com.sk89q.worldedit.command.ClipboardCommands#schematic() */ public class SchematicCommands { private final WorldEdit we; diff --git a/src/main/java/com/sk89q/worldedit/commands/ScriptingCommands.java b/src/main/java/com/sk89q/worldedit/command/ScriptingCommands.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/commands/ScriptingCommands.java rename to src/main/java/com/sk89q/worldedit/command/ScriptingCommands.java index 170ccfa88..452e6c2d2 100644 --- a/src/main/java/com/sk89q/worldedit/commands/ScriptingCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/ScriptingCommands.java @@ -1,101 +1,101 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.commands; - -import java.io.File; -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.Logging; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.*; -import com.sk89q.worldedit.*; - -/** - * Scripting commands. - * - * @author sk89q - */ -public class ScriptingCommands { - private final WorldEdit we; - - public ScriptingCommands(WorldEdit we) { - this.we = we; - } - - @Command( - aliases = { "cs" }, - usage = " [args...]", - desc = "Execute a CraftScript", - min = 1, - max = -1 - ) - @CommandPermissions("worldedit.scripting.execute") - @Logging(ALL) - public void execute(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - String[] scriptArgs = args.getSlice(1); - String name = args.getString(0); - - if (!player.hasPermission("worldedit.scripting.execute." + name)) { - player.printError("You don't have permission to use that script."); - return; - } - - session.setLastScript(name); - - File dir = we.getWorkingDirectoryFile(we.getConfiguration().scriptsDir); - File f = we.getSafeOpenFile(player, dir, name, "js", "js"); - - we.runScript(player, f, scriptArgs); - } - - @Command( - aliases = { ".s" }, - usage = "[args...]", - desc = "Execute last CraftScript", - min = 0, - max = -1 - ) - @CommandPermissions("worldedit.scripting.execute") - @Logging(ALL) - public void executeLast(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - String lastScript = session.getLastScript(); - - if (!player.hasPermission("worldedit.scripting.execute." + lastScript)) { - player.printError("You don't have permission to use that script."); - return; - } - - if (lastScript == null) { - player.printError("Use /cs with a script name first."); - return; - } - - String[] scriptArgs = args.getSlice(0); - - File dir = we.getWorkingDirectoryFile(we.getConfiguration().scriptsDir); - File f = we.getSafeOpenFile(player, dir, lastScript, "js", "js"); - - we.runScript(player, f, scriptArgs); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command; + +import java.io.File; +import com.sk89q.minecraft.util.commands.Command; +import com.sk89q.minecraft.util.commands.CommandContext; +import com.sk89q.minecraft.util.commands.CommandPermissions; +import com.sk89q.minecraft.util.commands.Logging; +import static com.sk89q.minecraft.util.commands.Logging.LogMode.*; +import com.sk89q.worldedit.*; + +/** + * Scripting commands. + * + * @author sk89q + */ +public class ScriptingCommands { + private final WorldEdit we; + + public ScriptingCommands(WorldEdit we) { + this.we = we; + } + + @Command( + aliases = { "cs" }, + usage = " [args...]", + desc = "Execute a CraftScript", + min = 1, + max = -1 + ) + @CommandPermissions("worldedit.scripting.execute") + @Logging(ALL) + public void execute(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + String[] scriptArgs = args.getSlice(1); + String name = args.getString(0); + + if (!player.hasPermission("worldedit.scripting.execute." + name)) { + player.printError("You don't have permission to use that script."); + return; + } + + session.setLastScript(name); + + File dir = we.getWorkingDirectoryFile(we.getConfiguration().scriptsDir); + File f = we.getSafeOpenFile(player, dir, name, "js", "js"); + + we.runScript(player, f, scriptArgs); + } + + @Command( + aliases = { ".s" }, + usage = "[args...]", + desc = "Execute last CraftScript", + min = 0, + max = -1 + ) + @CommandPermissions("worldedit.scripting.execute") + @Logging(ALL) + public void executeLast(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + String lastScript = session.getLastScript(); + + if (!player.hasPermission("worldedit.scripting.execute." + lastScript)) { + player.printError("You don't have permission to use that script."); + return; + } + + if (lastScript == null) { + player.printError("Use /cs with a script name first."); + return; + } + + String[] scriptArgs = args.getSlice(0); + + File dir = we.getWorkingDirectoryFile(we.getConfiguration().scriptsDir); + File f = we.getSafeOpenFile(player, dir, lastScript, "js", "js"); + + we.runScript(player, f, scriptArgs); + } +} diff --git a/src/main/java/com/sk89q/worldedit/commands/SelectionCommands.java b/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/commands/SelectionCommands.java rename to src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index b268467d0..6487909ca 100644 --- a/src/main/java/com/sk89q/worldedit/commands/SelectionCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -1,788 +1,788 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.commands; - -import static com.sk89q.minecraft.util.commands.Logging.LogMode.POSITION; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandAlias; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.Logging; -import com.sk89q.worldedit.Countable; -import com.sk89q.worldedit.CuboidClipboard; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.LocalWorld; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.Vector2D; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.blocks.BlockType; -import com.sk89q.worldedit.data.ChunkStore; -import com.sk89q.worldedit.regions.ConvexPolyhedralRegionSelector; -import com.sk89q.worldedit.regions.CuboidRegionSelector; -import com.sk89q.worldedit.regions.CylinderRegionSelector; -import com.sk89q.worldedit.regions.EllipsoidRegionSelector; -import com.sk89q.worldedit.regions.ExtendingCuboidRegionSelector; -import com.sk89q.worldedit.regions.Polygonal2DRegionSelector; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.regions.RegionOperationException; -import com.sk89q.worldedit.regions.RegionSelector; -import com.sk89q.worldedit.regions.SphereRegionSelector; - -/** - * Selection commands. - * - * @author sk89q - */ -public class SelectionCommands { - private final WorldEdit we; - - public SelectionCommands(WorldEdit we) { - this.we = we; - } - - @Command( - aliases = { "/pos1" }, - usage = "[coordinates]", - desc = "Set position 1", - min = 0, - max = 1 - ) - @Logging(POSITION) - @CommandPermissions("worldedit.selection.pos") - public void pos1(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - Vector pos; - - if (args.argsLength() == 1) { - if (args.getString(0).matches("-?\\d+,-?\\d+,-?\\d+")) { - String[] coords = args.getString(0).split(","); - pos = new Vector(Integer.parseInt(coords[0]), Integer.parseInt(coords[1]), Integer.parseInt(coords[2])); - } else { - player.printError("Invalid coordinates " + args.getString(0)); - return; - } - } else { - pos = player.getBlockIn(); - } - - if (!session.getRegionSelector(player.getWorld()).selectPrimary(pos)) { - player.printError("Position already set."); - return; - } - - session.getRegionSelector(player.getWorld()) - .explainPrimarySelection(player, session, pos); - } - - @Command( - aliases = { "/pos2" }, - usage = "[coordinates]", - desc = "Set position 2", - min = 0, - max = 1 - ) - @Logging(POSITION) - @CommandPermissions("worldedit.selection.pos") - public void pos2(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - Vector pos; - if (args.argsLength() == 1) { - if (args.getString(0).matches("-?\\d+,-?\\d+,-?\\d+")) { - String[] coords = args.getString(0).split(","); - pos = new Vector(Integer.parseInt(coords[0]), - Integer.parseInt(coords[1]), - Integer.parseInt(coords[2])); - } else { - player.printError("Invalid coordinates " + args.getString(0)); - return; - } - } else { - pos = player.getBlockIn(); - } - - if (!session.getRegionSelector(player.getWorld()).selectSecondary(pos)) { - player.printError("Position already set."); - return; - } - - session.getRegionSelector(player.getWorld()) - .explainSecondarySelection(player, session, pos); - } - - @Command( - aliases = { "/hpos1" }, - usage = "", - desc = "Set position 1 to targeted block", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.selection.hpos") - public void hpos1(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - Vector pos = player.getBlockTrace(300); - - if (pos != null) { - if (!session.getRegionSelector(player.getWorld()) - .selectPrimary(pos)) { - player.printError("Position already set."); - return; - } - - session.getRegionSelector(player.getWorld()) - .explainPrimarySelection(player, session, pos); - } else { - player.printError("No block in sight!"); - } - } - - @Command( - aliases = { "/hpos2" }, - usage = "", - desc = "Set position 2 to targeted block", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.selection.hpos") - public void hpos2(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - Vector pos = player.getBlockTrace(300); - - if (pos != null) { - if (!session.getRegionSelector(player.getWorld()) - .selectSecondary(pos)) { - player.printError("Position already set."); - return; - } - - session.getRegionSelector(player.getWorld()) - .explainSecondarySelection(player, session, pos); - } else { - player.printError("No block in sight!"); - } - } - - @Command( - aliases = { "/chunk" }, - usage = "[x,z coordinates]", - flags = "sc", - desc = "Set the selection to your current chunk.", - help = - "Set the selection to the chunk you are currently in.\n" + - "With the -s flag, your current selection is expanded\n" + - "to encompass all chunks that are part of it.\n\n" + - "Specifying coordinates will use those instead of your\n"+ - "current position. Use -c to specify chunk coordinates,\n" + - "otherwise full coordinates will be implied.\n" + - "(for example, the coordinates 5,5 are the same as -c 0,0)", - min = 0, - max = 1 - ) - @Logging(POSITION) - @CommandPermissions("worldedit.selection.chunk") - public void chunk(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - final Vector min; - final Vector max; - final LocalWorld world = player.getWorld(); - if (args.hasFlag('s')) { - Region region = session.getSelection(world); - - final Vector2D min2D = ChunkStore.toChunk(region.getMinimumPoint()); - final Vector2D max2D = ChunkStore.toChunk(region.getMaximumPoint()); - - min = new Vector(min2D.getBlockX() * 16, 0, min2D.getBlockZ() * 16); - max = new Vector(max2D.getBlockX() * 16 + 15, world.getMaxY(), max2D.getBlockZ() * 16 + 15); - - player.print("Chunks selected: (" - + min2D.getBlockX() + ", " + min2D.getBlockZ() + ") - (" - + max2D.getBlockX() + ", " + max2D.getBlockZ() + ")"); - } else { - final Vector2D min2D; - if (args.argsLength() == 1) { - // coords specified - String[] coords = args.getString(0).split(","); - if (coords.length != 2) { - throw new InsufficientArgumentsException("Invalid coordinates specified."); - } - int x = Integer.parseInt(coords[0]); - int z = Integer.parseInt(coords[1]); - Vector2D pos = new Vector2D(x, z); - min2D = (args.hasFlag('c')) ? pos : ChunkStore.toChunk(pos.toVector()); - } else { - // use player loc - min2D = ChunkStore.toChunk(player.getBlockIn()); - } - - min = new Vector(min2D.getBlockX() * 16, 0, min2D.getBlockZ() * 16); - max = min.add(15, world.getMaxY(), 15); - - player.print("Chunk selected: " - + min2D.getBlockX() + ", " + min2D.getBlockZ()); - } - - final CuboidRegionSelector selector; - if (session.getRegionSelector(world) instanceof ExtendingCuboidRegionSelector) { - selector = new ExtendingCuboidRegionSelector(world); - } else { - selector = new CuboidRegionSelector(world); - } - selector.selectPrimary(min); - selector.selectSecondary(max); - session.setRegionSelector(world, selector); - - session.dispatchCUISelection(player); - - } - - @Command( - aliases = { "/wand" }, - usage = "", - desc = "Get the wand object", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.wand") - public void wand(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - player.giveItem(we.getConfiguration().wandItem, 1); - player.print("Left click: select pos #1; Right click: select pos #2"); - } - - @Command( - aliases = { "toggleeditwand" }, - usage = "", - desc = "Toggle functionality of the edit wand", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.wand.toggle") - public void toggleWand(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - session.setToolControl(!session.isToolControlEnabled()); - - if (session.isToolControlEnabled()) { - player.print("Edit wand enabled."); - } else { - player.print("Edit wand disabled."); - } - } - - @Command( - aliases = { "/expand" }, - usage = " [reverse-amount] ", - desc = "Expand the selection area", - min = 1, - max = 3 - ) - @Logging(REGION) - @CommandPermissions("worldedit.selection.expand") - public void expand(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - // Special syntax (//expand vert) to expand the selection between - // sky and bedrock. - if (args.getString(0).equalsIgnoreCase("vert") - || args.getString(0).equalsIgnoreCase("vertical")) { - Region region = session.getSelection(player.getWorld()); - try { - int oldSize = region.getArea(); - region.expand( - new Vector(0, (player.getWorld().getMaxY() + 1), 0), - new Vector(0, -(player.getWorld().getMaxY() + 1), 0)); - session.getRegionSelector(player.getWorld()).learnChanges(); - int newSize = region.getArea(); - session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); - player.print("Region expanded " + (newSize - oldSize) - + " blocks [top-to-bottom]."); - } catch (RegionOperationException e) { - player.printError(e.getMessage()); - } - - return; - } - - List dirs = new ArrayList(); - int change = args.getInteger(0); - int reverseChange = 0; - - switch (args.argsLength()) { - case 2: - // Either a reverse amount or a direction - try { - reverseChange = args.getInteger(1); - dirs.add(we.getDirection(player, "me")); - } catch (NumberFormatException e) { - if (args.getString(1).contains(",")) { - String[] split = args.getString(1).split(","); - for (String s : split) { - dirs.add(we.getDirection(player, s.toLowerCase())); - } - } else { - dirs.add(we.getDirection(player, args.getString(1).toLowerCase())); - } - } - break; - - case 3: - // Both reverse amount and direction - reverseChange = args.getInteger(1); - if (args.getString(2).contains(",")) { - String[] split = args.getString(2).split(","); - for (String s : split) { - dirs.add(we.getDirection(player, s.toLowerCase())); - } - } else { - dirs.add(we.getDirection(player, args.getString(2).toLowerCase())); - } - break; - - default: - dirs.add(we.getDirection(player, "me")); - break; - - } - - Region region = session.getSelection(player.getWorld()); - int oldSize = region.getArea(); - - if (reverseChange == 0) { - for (Vector dir : dirs) { - region.expand(dir.multiply(change)); - } - } else { - for (Vector dir : dirs) { - region.expand(dir.multiply(change), dir.multiply(-reverseChange)); - } - } - - session.getRegionSelector(player.getWorld()).learnChanges(); - int newSize = region.getArea(); - - session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); - - player.print("Region expanded " + (newSize - oldSize) + " blocks."); - } - - @Command( - aliases = { "/contract" }, - usage = " [reverse-amount] [direction]", - desc = "Contract the selection area", - min = 1, - max = 3 - ) - @Logging(REGION) - @CommandPermissions("worldedit.selection.contract") - public void contract(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - List dirs = new ArrayList(); - int change = args.getInteger(0); - int reverseChange = 0; - - switch (args.argsLength()) { - case 2: - // Either a reverse amount or a direction - try { - reverseChange = args.getInteger(1); - dirs.add(we.getDirection(player, "me")); - } catch (NumberFormatException e) { - if (args.getString(1).contains(",")) { - String[] split = args.getString(1).split(","); - for (String s : split) { - dirs.add(we.getDirection(player, s.toLowerCase())); - } - } else { - dirs.add(we.getDirection(player, args.getString(1).toLowerCase())); - } - } - break; - - case 3: - // Both reverse amount and direction - reverseChange = args.getInteger(1); - if (args.getString(2).contains(",")) { - String[] split = args.getString(2).split(","); - for (String s : split) { - dirs.add(we.getDirection(player, s.toLowerCase())); - } - } else { - dirs.add(we.getDirection(player, args.getString(2).toLowerCase())); - } - break; - - default: - dirs.add(we.getDirection(player, "me")); - break; - } - - try { - Region region = session.getSelection(player.getWorld()); - int oldSize = region.getArea(); - if (reverseChange == 0) { - for (Vector dir : dirs) { - region.contract(dir.multiply(change)); - } - } else { - for (Vector dir : dirs) { - region.contract(dir.multiply(change), dir.multiply(-reverseChange)); - } - } - session.getRegionSelector(player.getWorld()).learnChanges(); - int newSize = region.getArea(); - - session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); - - - player.print("Region contracted " + (oldSize - newSize) + " blocks."); - } catch (RegionOperationException e) { - player.printError(e.getMessage()); - } - } - - @Command( - aliases = { "/shift" }, - usage = " [direction]", - desc = "Shift the selection area", - min = 1, - max = 2 - ) - @Logging(REGION) - @CommandPermissions("worldedit.selection.shift") - public void shift(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - List dirs = new ArrayList(); - int change = args.getInteger(0); - if (args.argsLength() == 2) { - if (args.getString(1).contains(",")) { - for (String s : args.getString(1).split(",")) { - dirs.add(we.getDirection(player, s.toLowerCase())); - } - } else { - dirs.add(we.getDirection(player, args.getString(1).toLowerCase())); - } - } else { - dirs.add(we.getDirection(player, "me")); - } - - try { - Region region = session.getSelection(player.getWorld()); - - for (Vector dir : dirs) { - region.shift(dir.multiply(change)); - } - - session.getRegionSelector(player.getWorld()).learnChanges(); - - session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); - - player.print("Region shifted."); - } catch (RegionOperationException e) { - player.printError(e.getMessage()); - } - } - - @Command( - aliases = { "/outset" }, - usage = "", - desc = "Outset the selection area", - help = - "Expands the selection by the given amount in all directions.\n" + - "Flags:\n" + - " -h only expand horizontally\n" + - " -v only expand vertically\n", - flags = "hv", - min = 1, - max = 1 - ) - @Logging(REGION) - @CommandPermissions("worldedit.selection.outset") - public void outset(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - Region region = session.getSelection(player.getWorld()); - region.expand(getChangesForEachDir(args)); - session.getRegionSelector(player.getWorld()).learnChanges(); - session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); - player.print("Region outset."); - } - - @Command( - aliases = { "/inset" }, - usage = "", - desc = "Inset the selection area", - help = - "Contracts the selection by the given amount in all directions.\n" + - "Flags:\n" + - " -h only contract horizontally\n" + - " -v only contract vertically\n", - flags = "hv", - min = 1, - max = 1 - ) - @Logging(REGION) - @CommandPermissions("worldedit.selection.inset") - public void inset(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - Region region = session.getSelection(player.getWorld()); - region.contract(getChangesForEachDir(args)); - session.getRegionSelector(player.getWorld()).learnChanges(); - session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); - player.print("Region inset."); - } - - private Vector[] getChangesForEachDir(CommandContext args) { - List changes = new ArrayList(6); - int change = args.getInteger(0); - - if (!args.hasFlag('h')) { - changes.add((new Vector(0, 1, 0)).multiply(change)); - changes.add((new Vector(0, -1, 0)).multiply(change)); - } - - if (!args.hasFlag('v')) { - changes.add((new Vector(1, 0, 0)).multiply(change)); - changes.add((new Vector(-1, 0, 0)).multiply(change)); - changes.add((new Vector(0, 0, 1)).multiply(change)); - changes.add((new Vector(0, 0, -1)).multiply(change)); - } - - return changes.toArray(new Vector[0]); - } - - @Command( - aliases = { "/size" }, - flags = "c", - usage = "", - desc = "Get information about the selection", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.selection.size") - public void size(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - if (args.hasFlag('c')) { - CuboidClipboard clipboard = session.getClipboard(); - Vector size = clipboard.getSize(); - Vector offset = clipboard.getOffset(); - - player.print("Size: " + size); - player.print("Offset: " + offset); - player.print("Cuboid distance: " + size.distance(Vector.ONE)); - player.print("# of blocks: " - + (int) (size.getX() * size.getY() * size.getZ())); - return; - } - - Region region = session.getSelection(player.getWorld()); - Vector size = region.getMaximumPoint() - .subtract(region.getMinimumPoint()) - .add(1, 1, 1); - - player.print("Type: " + session.getRegionSelector(player.getWorld()) - .getTypeName()); - - for (String line : session.getRegionSelector(player.getWorld()) - .getInformationLines()) { - player.print(line); - } - - player.print("Size: " + size); - player.print("Cuboid distance: " + region.getMaximumPoint() - .distance(region.getMinimumPoint())); - player.print("# of blocks: " + region.getArea()); - } - - - @Command( - aliases = { "/count" }, - usage = "", - desc = "Counts the number of a certain type of block", - flags = "d", - min = 1, - max = 1 - ) - @CommandPermissions("worldedit.analysis.count") - public void count(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - boolean useData = args.hasFlag('d'); - if (args.getString(0).contains(":")) { - useData = true; //override d flag, if they specified data they want it - } - if (useData) { - Set searchBlocks = we.getBlocks(player, args.getString(0), true); - int count = editSession.countBlocks(session.getSelection(player.getWorld()), searchBlocks); - player.print("Counted: " + count); - } else { - Set searchIDs = we.getBlockIDs(player, args.getString(0), true); - int count = editSession.countBlock(session.getSelection(player.getWorld()), searchIDs); - player.print("Counted: " + count); - } - } - - @Command( - aliases = { "/distr" }, - usage = "", - desc = "Get the distribution of blocks in the selection", - help = - "Gets the distribution of blocks in the selection.\n" + - "The -c flag gets the distribution of your clipboard.\n" + - "The -d flag separates blocks by data", - flags = "cd", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.analysis.distr") - public void distr(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - int size; - boolean useData = args.hasFlag('d'); - List> distribution = null; - List> distributionData = null; - - if (args.hasFlag('c')) { - CuboidClipboard clip = session.getClipboard(); - if (useData) { - distributionData = clip.getBlockDistributionWithData(); - } else { - distribution = clip.getBlockDistribution(); - } - size = clip.getHeight() * clip.getLength() * clip.getWidth(); - } else { - if (useData) { - distributionData = editSession.getBlockDistributionWithData(session.getSelection(player.getWorld())); - } else { - distribution = editSession.getBlockDistribution(session.getSelection(player.getWorld())); - } - size = session.getSelection(player.getWorld()).getArea(); - } - - if ((useData && distributionData.size() <= 0) - || (!useData && distribution.size() <= 0)) { // *Should* always be false - player.printError("No blocks counted."); - return; - } - - player.print("# total blocks: " + size); - - if (useData) { - for (Countable c : distributionData) { - String name = BlockType.fromID(c.getID().getId()).getName(); - String str = String.format("%-7s (%.3f%%) %s #%d:%d", - String.valueOf(c.getAmount()), - c.getAmount() / (double) size * 100, - name == null ? "Unknown" : name, - c.getID().getType(), c.getID().getData()); - player.print(str); - } - } else { - for (Countable c : distribution) { - BlockType block = BlockType.fromID(c.getID()); - String str = String.format("%-7s (%.3f%%) %s #%d", - String.valueOf(c.getAmount()), - c.getAmount() / (double) size * 100, - block == null ? "Unknown" : block.getName(), c.getID()); - player.print(str); - } - } - } - - @Command( - aliases = { "/sel", ";" }, - usage = "[cuboid|extend|poly|ellipsoid|sphere|cyl|convex]", - desc = "Choose a region selector", - min = 0, - max = 1 - ) - public void select(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - final LocalWorld world = player.getWorld(); - if (args.argsLength() == 0) { - session.getRegionSelector(world).clear(); - session.dispatchCUISelection(player); - player.print("Selection cleared."); - return; - } - - final String typeName = args.getString(0); - final RegionSelector oldSelector = session.getRegionSelector(world); - - final RegionSelector selector; - if (typeName.equalsIgnoreCase("cuboid")) { - selector = new CuboidRegionSelector(oldSelector); - player.print("Cuboid: left click for point 1, right click for point 2"); - } else if (typeName.equalsIgnoreCase("extend")) { - selector = new ExtendingCuboidRegionSelector(oldSelector); - player.print("Cuboid: left click for a starting point, right click to extend"); - } else if (typeName.equalsIgnoreCase("poly")) { - int maxPoints = we.getMaximumPolygonalPoints(player); - selector = new Polygonal2DRegionSelector(oldSelector, maxPoints); - player.print("2D polygon selector: Left/right click to add a point."); - if (maxPoints > -1) { - player.print(maxPoints + " points maximum."); - } - } else if (typeName.equalsIgnoreCase("ellipsoid")) { - selector = new EllipsoidRegionSelector(oldSelector); - player.print("Ellipsoid selector: left click=center, right click to extend"); - } else if (typeName.equalsIgnoreCase("sphere")) { - selector = new SphereRegionSelector(oldSelector); - player.print("Sphere selector: left click=center, right click to set radius"); - } else if (typeName.equalsIgnoreCase("cyl")) { - selector = new CylinderRegionSelector(oldSelector); - player.print("Cylindrical selector: Left click=center, right click to extend."); - } else if (typeName.equalsIgnoreCase("convex") || typeName.equalsIgnoreCase("hull") || typeName.equalsIgnoreCase("polyhedron")) { - int maxVertices = we.getMaximumPolyhedronPoints(player); - selector = new ConvexPolyhedralRegionSelector(oldSelector, maxVertices); - player.print("Convex polyhedral selector: Left click=First vertex, right click to add more."); - } else { - player.printError("Only cuboid|extend|poly|ellipsoid|sphere|cyl|convex are accepted."); - return; - } - - session.setRegionSelector(world, selector); - session.dispatchCUISelection(player); - } - - @Command(aliases = {"/desel", "/deselect"}, desc = "Deselect the current selection") - @CommandAlias("/sel") - public void deselect() { - - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command; + +import static com.sk89q.minecraft.util.commands.Logging.LogMode.POSITION; +import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import com.sk89q.minecraft.util.commands.Command; +import com.sk89q.minecraft.util.commands.CommandAlias; +import com.sk89q.minecraft.util.commands.CommandContext; +import com.sk89q.minecraft.util.commands.CommandPermissions; +import com.sk89q.minecraft.util.commands.Logging; +import com.sk89q.worldedit.util.Countable; +import com.sk89q.worldedit.CuboidClipboard; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockType; +import com.sk89q.worldedit.world.storage.ChunkStore; +import com.sk89q.worldedit.regions.selector.ConvexPolyhedralRegionSelector; +import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; +import com.sk89q.worldedit.regions.selector.CylinderRegionSelector; +import com.sk89q.worldedit.regions.selector.EllipsoidRegionSelector; +import com.sk89q.worldedit.regions.selector.ExtendingCuboidRegionSelector; +import com.sk89q.worldedit.regions.selector.Polygonal2DRegionSelector; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionOperationException; +import com.sk89q.worldedit.regions.selector.RegionSelector; +import com.sk89q.worldedit.regions.selector.SphereRegionSelector; + +/** + * Selection commands. + * + * @author sk89q + */ +public class SelectionCommands { + private final WorldEdit we; + + public SelectionCommands(WorldEdit we) { + this.we = we; + } + + @Command( + aliases = { "/pos1" }, + usage = "[coordinates]", + desc = "Set position 1", + min = 0, + max = 1 + ) + @Logging(POSITION) + @CommandPermissions("worldedit.selection.pos") + public void pos1(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + Vector pos; + + if (args.argsLength() == 1) { + if (args.getString(0).matches("-?\\d+,-?\\d+,-?\\d+")) { + String[] coords = args.getString(0).split(","); + pos = new Vector(Integer.parseInt(coords[0]), Integer.parseInt(coords[1]), Integer.parseInt(coords[2])); + } else { + player.printError("Invalid coordinates " + args.getString(0)); + return; + } + } else { + pos = player.getBlockIn(); + } + + if (!session.getRegionSelector(player.getWorld()).selectPrimary(pos)) { + player.printError("Position already set."); + return; + } + + session.getRegionSelector(player.getWorld()) + .explainPrimarySelection(player, session, pos); + } + + @Command( + aliases = { "/pos2" }, + usage = "[coordinates]", + desc = "Set position 2", + min = 0, + max = 1 + ) + @Logging(POSITION) + @CommandPermissions("worldedit.selection.pos") + public void pos2(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + Vector pos; + if (args.argsLength() == 1) { + if (args.getString(0).matches("-?\\d+,-?\\d+,-?\\d+")) { + String[] coords = args.getString(0).split(","); + pos = new Vector(Integer.parseInt(coords[0]), + Integer.parseInt(coords[1]), + Integer.parseInt(coords[2])); + } else { + player.printError("Invalid coordinates " + args.getString(0)); + return; + } + } else { + pos = player.getBlockIn(); + } + + if (!session.getRegionSelector(player.getWorld()).selectSecondary(pos)) { + player.printError("Position already set."); + return; + } + + session.getRegionSelector(player.getWorld()) + .explainSecondarySelection(player, session, pos); + } + + @Command( + aliases = { "/hpos1" }, + usage = "", + desc = "Set position 1 to targeted block", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.selection.hpos") + public void hpos1(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + Vector pos = player.getBlockTrace(300); + + if (pos != null) { + if (!session.getRegionSelector(player.getWorld()) + .selectPrimary(pos)) { + player.printError("Position already set."); + return; + } + + session.getRegionSelector(player.getWorld()) + .explainPrimarySelection(player, session, pos); + } else { + player.printError("No block in sight!"); + } + } + + @Command( + aliases = { "/hpos2" }, + usage = "", + desc = "Set position 2 to targeted block", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.selection.hpos") + public void hpos2(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + Vector pos = player.getBlockTrace(300); + + if (pos != null) { + if (!session.getRegionSelector(player.getWorld()) + .selectSecondary(pos)) { + player.printError("Position already set."); + return; + } + + session.getRegionSelector(player.getWorld()) + .explainSecondarySelection(player, session, pos); + } else { + player.printError("No block in sight!"); + } + } + + @Command( + aliases = { "/chunk" }, + usage = "[x,z coordinates]", + flags = "sc", + desc = "Set the selection to your current chunk.", + help = + "Set the selection to the chunk you are currently in.\n" + + "With the -s flag, your current selection is expanded\n" + + "to encompass all chunks that are part of it.\n\n" + + "Specifying coordinates will use those instead of your\n"+ + "current position. Use -c to specify chunk coordinates,\n" + + "otherwise full coordinates will be implied.\n" + + "(for example, the coordinates 5,5 are the same as -c 0,0)", + min = 0, + max = 1 + ) + @Logging(POSITION) + @CommandPermissions("worldedit.selection.chunk") + public void chunk(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + final Vector min; + final Vector max; + final LocalWorld world = player.getWorld(); + if (args.hasFlag('s')) { + Region region = session.getSelection(world); + + final Vector2D min2D = ChunkStore.toChunk(region.getMinimumPoint()); + final Vector2D max2D = ChunkStore.toChunk(region.getMaximumPoint()); + + min = new Vector(min2D.getBlockX() * 16, 0, min2D.getBlockZ() * 16); + max = new Vector(max2D.getBlockX() * 16 + 15, world.getMaxY(), max2D.getBlockZ() * 16 + 15); + + player.print("Chunks selected: (" + + min2D.getBlockX() + ", " + min2D.getBlockZ() + ") - (" + + max2D.getBlockX() + ", " + max2D.getBlockZ() + ")"); + } else { + final Vector2D min2D; + if (args.argsLength() == 1) { + // coords specified + String[] coords = args.getString(0).split(","); + if (coords.length != 2) { + throw new InsufficientArgumentsException("Invalid coordinates specified."); + } + int x = Integer.parseInt(coords[0]); + int z = Integer.parseInt(coords[1]); + Vector2D pos = new Vector2D(x, z); + min2D = (args.hasFlag('c')) ? pos : ChunkStore.toChunk(pos.toVector()); + } else { + // use player loc + min2D = ChunkStore.toChunk(player.getBlockIn()); + } + + min = new Vector(min2D.getBlockX() * 16, 0, min2D.getBlockZ() * 16); + max = min.add(15, world.getMaxY(), 15); + + player.print("Chunk selected: " + + min2D.getBlockX() + ", " + min2D.getBlockZ()); + } + + final CuboidRegionSelector selector; + if (session.getRegionSelector(world) instanceof ExtendingCuboidRegionSelector) { + selector = new ExtendingCuboidRegionSelector(world); + } else { + selector = new CuboidRegionSelector(world); + } + selector.selectPrimary(min); + selector.selectSecondary(max); + session.setRegionSelector(world, selector); + + session.dispatchCUISelection(player); + + } + + @Command( + aliases = { "/wand" }, + usage = "", + desc = "Get the wand object", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.wand") + public void wand(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + player.giveItem(we.getConfiguration().wandItem, 1); + player.print("Left click: select pos #1; Right click: select pos #2"); + } + + @Command( + aliases = { "toggleeditwand" }, + usage = "", + desc = "Toggle functionality of the edit wand", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.wand.toggle") + public void toggleWand(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + session.setToolControl(!session.isToolControlEnabled()); + + if (session.isToolControlEnabled()) { + player.print("Edit wand enabled."); + } else { + player.print("Edit wand disabled."); + } + } + + @Command( + aliases = { "/expand" }, + usage = " [reverse-amount] ", + desc = "Expand the selection area", + min = 1, + max = 3 + ) + @Logging(REGION) + @CommandPermissions("worldedit.selection.expand") + public void expand(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + // Special syntax (//expand vert) to expand the selection between + // sky and bedrock. + if (args.getString(0).equalsIgnoreCase("vert") + || args.getString(0).equalsIgnoreCase("vertical")) { + Region region = session.getSelection(player.getWorld()); + try { + int oldSize = region.getArea(); + region.expand( + new Vector(0, (player.getWorld().getMaxY() + 1), 0), + new Vector(0, -(player.getWorld().getMaxY() + 1), 0)); + session.getRegionSelector(player.getWorld()).learnChanges(); + int newSize = region.getArea(); + session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); + player.print("Region expanded " + (newSize - oldSize) + + " blocks [top-to-bottom]."); + } catch (RegionOperationException e) { + player.printError(e.getMessage()); + } + + return; + } + + List dirs = new ArrayList(); + int change = args.getInteger(0); + int reverseChange = 0; + + switch (args.argsLength()) { + case 2: + // Either a reverse amount or a direction + try { + reverseChange = args.getInteger(1); + dirs.add(we.getDirection(player, "me")); + } catch (NumberFormatException e) { + if (args.getString(1).contains(",")) { + String[] split = args.getString(1).split(","); + for (String s : split) { + dirs.add(we.getDirection(player, s.toLowerCase())); + } + } else { + dirs.add(we.getDirection(player, args.getString(1).toLowerCase())); + } + } + break; + + case 3: + // Both reverse amount and direction + reverseChange = args.getInteger(1); + if (args.getString(2).contains(",")) { + String[] split = args.getString(2).split(","); + for (String s : split) { + dirs.add(we.getDirection(player, s.toLowerCase())); + } + } else { + dirs.add(we.getDirection(player, args.getString(2).toLowerCase())); + } + break; + + default: + dirs.add(we.getDirection(player, "me")); + break; + + } + + Region region = session.getSelection(player.getWorld()); + int oldSize = region.getArea(); + + if (reverseChange == 0) { + for (Vector dir : dirs) { + region.expand(dir.multiply(change)); + } + } else { + for (Vector dir : dirs) { + region.expand(dir.multiply(change), dir.multiply(-reverseChange)); + } + } + + session.getRegionSelector(player.getWorld()).learnChanges(); + int newSize = region.getArea(); + + session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); + + player.print("Region expanded " + (newSize - oldSize) + " blocks."); + } + + @Command( + aliases = { "/contract" }, + usage = " [reverse-amount] [direction]", + desc = "Contract the selection area", + min = 1, + max = 3 + ) + @Logging(REGION) + @CommandPermissions("worldedit.selection.contract") + public void contract(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + List dirs = new ArrayList(); + int change = args.getInteger(0); + int reverseChange = 0; + + switch (args.argsLength()) { + case 2: + // Either a reverse amount or a direction + try { + reverseChange = args.getInteger(1); + dirs.add(we.getDirection(player, "me")); + } catch (NumberFormatException e) { + if (args.getString(1).contains(",")) { + String[] split = args.getString(1).split(","); + for (String s : split) { + dirs.add(we.getDirection(player, s.toLowerCase())); + } + } else { + dirs.add(we.getDirection(player, args.getString(1).toLowerCase())); + } + } + break; + + case 3: + // Both reverse amount and direction + reverseChange = args.getInteger(1); + if (args.getString(2).contains(",")) { + String[] split = args.getString(2).split(","); + for (String s : split) { + dirs.add(we.getDirection(player, s.toLowerCase())); + } + } else { + dirs.add(we.getDirection(player, args.getString(2).toLowerCase())); + } + break; + + default: + dirs.add(we.getDirection(player, "me")); + break; + } + + try { + Region region = session.getSelection(player.getWorld()); + int oldSize = region.getArea(); + if (reverseChange == 0) { + for (Vector dir : dirs) { + region.contract(dir.multiply(change)); + } + } else { + for (Vector dir : dirs) { + region.contract(dir.multiply(change), dir.multiply(-reverseChange)); + } + } + session.getRegionSelector(player.getWorld()).learnChanges(); + int newSize = region.getArea(); + + session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); + + + player.print("Region contracted " + (oldSize - newSize) + " blocks."); + } catch (RegionOperationException e) { + player.printError(e.getMessage()); + } + } + + @Command( + aliases = { "/shift" }, + usage = " [direction]", + desc = "Shift the selection area", + min = 1, + max = 2 + ) + @Logging(REGION) + @CommandPermissions("worldedit.selection.shift") + public void shift(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + List dirs = new ArrayList(); + int change = args.getInteger(0); + if (args.argsLength() == 2) { + if (args.getString(1).contains(",")) { + for (String s : args.getString(1).split(",")) { + dirs.add(we.getDirection(player, s.toLowerCase())); + } + } else { + dirs.add(we.getDirection(player, args.getString(1).toLowerCase())); + } + } else { + dirs.add(we.getDirection(player, "me")); + } + + try { + Region region = session.getSelection(player.getWorld()); + + for (Vector dir : dirs) { + region.shift(dir.multiply(change)); + } + + session.getRegionSelector(player.getWorld()).learnChanges(); + + session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); + + player.print("Region shifted."); + } catch (RegionOperationException e) { + player.printError(e.getMessage()); + } + } + + @Command( + aliases = { "/outset" }, + usage = "", + desc = "Outset the selection area", + help = + "Expands the selection by the given amount in all directions.\n" + + "Flags:\n" + + " -h only expand horizontally\n" + + " -v only expand vertically\n", + flags = "hv", + min = 1, + max = 1 + ) + @Logging(REGION) + @CommandPermissions("worldedit.selection.outset") + public void outset(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + Region region = session.getSelection(player.getWorld()); + region.expand(getChangesForEachDir(args)); + session.getRegionSelector(player.getWorld()).learnChanges(); + session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); + player.print("Region outset."); + } + + @Command( + aliases = { "/inset" }, + usage = "", + desc = "Inset the selection area", + help = + "Contracts the selection by the given amount in all directions.\n" + + "Flags:\n" + + " -h only contract horizontally\n" + + " -v only contract vertically\n", + flags = "hv", + min = 1, + max = 1 + ) + @Logging(REGION) + @CommandPermissions("worldedit.selection.inset") + public void inset(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + Region region = session.getSelection(player.getWorld()); + region.contract(getChangesForEachDir(args)); + session.getRegionSelector(player.getWorld()).learnChanges(); + session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); + player.print("Region inset."); + } + + private Vector[] getChangesForEachDir(CommandContext args) { + List changes = new ArrayList(6); + int change = args.getInteger(0); + + if (!args.hasFlag('h')) { + changes.add((new Vector(0, 1, 0)).multiply(change)); + changes.add((new Vector(0, -1, 0)).multiply(change)); + } + + if (!args.hasFlag('v')) { + changes.add((new Vector(1, 0, 0)).multiply(change)); + changes.add((new Vector(-1, 0, 0)).multiply(change)); + changes.add((new Vector(0, 0, 1)).multiply(change)); + changes.add((new Vector(0, 0, -1)).multiply(change)); + } + + return changes.toArray(new Vector[0]); + } + + @Command( + aliases = { "/size" }, + flags = "c", + usage = "", + desc = "Get information about the selection", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.selection.size") + public void size(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + if (args.hasFlag('c')) { + CuboidClipboard clipboard = session.getClipboard(); + Vector size = clipboard.getSize(); + Vector offset = clipboard.getOffset(); + + player.print("Size: " + size); + player.print("Offset: " + offset); + player.print("Cuboid distance: " + size.distance(Vector.ONE)); + player.print("# of blocks: " + + (int) (size.getX() * size.getY() * size.getZ())); + return; + } + + Region region = session.getSelection(player.getWorld()); + Vector size = region.getMaximumPoint() + .subtract(region.getMinimumPoint()) + .add(1, 1, 1); + + player.print("Type: " + session.getRegionSelector(player.getWorld()) + .getTypeName()); + + for (String line : session.getRegionSelector(player.getWorld()) + .getInformationLines()) { + player.print(line); + } + + player.print("Size: " + size); + player.print("Cuboid distance: " + region.getMaximumPoint() + .distance(region.getMinimumPoint())); + player.print("# of blocks: " + region.getArea()); + } + + + @Command( + aliases = { "/count" }, + usage = "", + desc = "Counts the number of a certain type of block", + flags = "d", + min = 1, + max = 1 + ) + @CommandPermissions("worldedit.analysis.count") + public void count(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + boolean useData = args.hasFlag('d'); + if (args.getString(0).contains(":")) { + useData = true; //override d flag, if they specified data they want it + } + if (useData) { + Set searchBlocks = we.getBlocks(player, args.getString(0), true); + int count = editSession.countBlocks(session.getSelection(player.getWorld()), searchBlocks); + player.print("Counted: " + count); + } else { + Set searchIDs = we.getBlockIDs(player, args.getString(0), true); + int count = editSession.countBlock(session.getSelection(player.getWorld()), searchIDs); + player.print("Counted: " + count); + } + } + + @Command( + aliases = { "/distr" }, + usage = "", + desc = "Get the distribution of blocks in the selection", + help = + "Gets the distribution of blocks in the selection.\n" + + "The -c flag gets the distribution of your clipboard.\n" + + "The -d flag separates blocks by data", + flags = "cd", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.analysis.distr") + public void distr(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + int size; + boolean useData = args.hasFlag('d'); + List> distribution = null; + List> distributionData = null; + + if (args.hasFlag('c')) { + CuboidClipboard clip = session.getClipboard(); + if (useData) { + distributionData = clip.getBlockDistributionWithData(); + } else { + distribution = clip.getBlockDistribution(); + } + size = clip.getHeight() * clip.getLength() * clip.getWidth(); + } else { + if (useData) { + distributionData = editSession.getBlockDistributionWithData(session.getSelection(player.getWorld())); + } else { + distribution = editSession.getBlockDistribution(session.getSelection(player.getWorld())); + } + size = session.getSelection(player.getWorld()).getArea(); + } + + if ((useData && distributionData.size() <= 0) + || (!useData && distribution.size() <= 0)) { // *Should* always be false + player.printError("No blocks counted."); + return; + } + + player.print("# total blocks: " + size); + + if (useData) { + for (Countable c : distributionData) { + String name = BlockType.fromID(c.getID().getId()).getName(); + String str = String.format("%-7s (%.3f%%) %s #%d:%d", + String.valueOf(c.getAmount()), + c.getAmount() / (double) size * 100, + name == null ? "Unknown" : name, + c.getID().getType(), c.getID().getData()); + player.print(str); + } + } else { + for (Countable c : distribution) { + BlockType block = BlockType.fromID(c.getID()); + String str = String.format("%-7s (%.3f%%) %s #%d", + String.valueOf(c.getAmount()), + c.getAmount() / (double) size * 100, + block == null ? "Unknown" : block.getName(), c.getID()); + player.print(str); + } + } + } + + @Command( + aliases = { "/sel", ";" }, + usage = "[cuboid|extend|poly|ellipsoid|sphere|cyl|convex]", + desc = "Choose a region selector", + min = 0, + max = 1 + ) + public void select(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + final LocalWorld world = player.getWorld(); + if (args.argsLength() == 0) { + session.getRegionSelector(world).clear(); + session.dispatchCUISelection(player); + player.print("Selection cleared."); + return; + } + + final String typeName = args.getString(0); + final RegionSelector oldSelector = session.getRegionSelector(world); + + final RegionSelector selector; + if (typeName.equalsIgnoreCase("cuboid")) { + selector = new CuboidRegionSelector(oldSelector); + player.print("Cuboid: left click for point 1, right click for point 2"); + } else if (typeName.equalsIgnoreCase("extend")) { + selector = new ExtendingCuboidRegionSelector(oldSelector); + player.print("Cuboid: left click for a starting point, right click to extend"); + } else if (typeName.equalsIgnoreCase("poly")) { + int maxPoints = we.getMaximumPolygonalPoints(player); + selector = new Polygonal2DRegionSelector(oldSelector, maxPoints); + player.print("2D polygon selector: Left/right click to add a point."); + if (maxPoints > -1) { + player.print(maxPoints + " points maximum."); + } + } else if (typeName.equalsIgnoreCase("ellipsoid")) { + selector = new EllipsoidRegionSelector(oldSelector); + player.print("Ellipsoid selector: left click=center, right click to extend"); + } else if (typeName.equalsIgnoreCase("sphere")) { + selector = new SphereRegionSelector(oldSelector); + player.print("Sphere selector: left click=center, right click to set radius"); + } else if (typeName.equalsIgnoreCase("cyl")) { + selector = new CylinderRegionSelector(oldSelector); + player.print("Cylindrical selector: Left click=center, right click to extend."); + } else if (typeName.equalsIgnoreCase("convex") || typeName.equalsIgnoreCase("hull") || typeName.equalsIgnoreCase("polyhedron")) { + int maxVertices = we.getMaximumPolyhedronPoints(player); + selector = new ConvexPolyhedralRegionSelector(oldSelector, maxVertices); + player.print("Convex polyhedral selector: Left click=First vertex, right click to add more."); + } else { + player.printError("Only cuboid|extend|poly|ellipsoid|sphere|cyl|convex are accepted."); + return; + } + + session.setRegionSelector(world, selector); + session.dispatchCUISelection(player); + } + + @Command(aliases = {"/desel", "/deselect"}, desc = "Deselect the current selection") + @CommandAlias("/sel") + public void deselect() { + + } +} diff --git a/src/main/java/com/sk89q/worldedit/commands/SnapshotCommands.java b/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/commands/SnapshotCommands.java rename to src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java index b7e8e9648..ef818977c 100644 --- a/src/main/java/com/sk89q/worldedit/commands/SnapshotCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java @@ -1,272 +1,272 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.commands; - -import java.io.File; -import java.io.IOException; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.List; -import java.util.logging.Logger; -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.data.MissingWorldException; -import com.sk89q.worldedit.snapshots.InvalidSnapshotException; -import com.sk89q.worldedit.snapshots.Snapshot; - -/** - * Snapshot commands. - * - * @author sk89q - */ -public class SnapshotCommands { - private static final Logger logger = Logger.getLogger("Minecraft.WorldEdit"); - private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); - - private final WorldEdit we; - - public SnapshotCommands(WorldEdit we) { - this.we = we; - } - - @Command( - aliases = { "list" }, - usage = "[num]", - desc = "List snapshots", - min = 0, - max = 1 - ) - @CommandPermissions("worldedit.snapshots.list") - public void list(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - LocalConfiguration config = we.getConfiguration(); - - if (config.snapshotRepo == null) { - player.printError("Snapshot/backup restore is not configured."); - return; - } - - try { - List snapshots = config.snapshotRepo.getSnapshots(true, player.getWorld().getName()); - - if (snapshots.size() > 0) { - - int num = args.argsLength() > 0 ? Math.min(40, Math.max(5, args.getInteger(0))) : 5; - - player.print("Snapshots for world: '" + player.getWorld().getName() + "'"); - for (byte i = 0; i < Math.min(num, snapshots.size()); i++) { - player.print((i + 1) + ". " + snapshots.get(i).getName()); - } - - player.print("Use /snap use [snapshot] or /snap use latest."); - } else { - player.printError("No snapshots are available. See console for details."); - - // Okay, let's toss some debugging information! - File dir = config.snapshotRepo.getDirectory(); - - try { - logger.info("WorldEdit found no snapshots: looked in: " - + dir.getCanonicalPath()); - } catch (IOException e) { - logger.info("WorldEdit found no snapshots: looked in " - + "(NON-RESOLVABLE PATH - does it exist?): " - + dir.getPath()); - } - } - } catch (MissingWorldException ex) { - player.printError("No snapshots were found for this world."); - } - } - - @Command( - aliases = { "use" }, - usage = "", - desc = "Choose a snapshot to use", - min = 1, - max = 1 - ) - @CommandPermissions("worldedit.snapshots.restore") - public void use(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - LocalConfiguration config = we.getConfiguration(); - - if (config.snapshotRepo == null) { - player.printError("Snapshot/backup restore is not configured."); - return; - } - - String name = args.getString(0); - - // Want the latest snapshot? - if (name.equalsIgnoreCase("latest")) { - try { - Snapshot snapshot = config.snapshotRepo.getDefaultSnapshot(player.getWorld().getName()); - - if (snapshot != null) { - session.setSnapshot(null); - player.print("Now using newest snapshot."); - } else { - player.printError("No snapshots were found."); - } - } catch (MissingWorldException ex) { - player.printError("No snapshots were found for this world."); - } - } else { - try { - session.setSnapshot(config.snapshotRepo.getSnapshot(name)); - player.print("Snapshot set to: " + name); - } catch (InvalidSnapshotException e) { - player.printError("That snapshot does not exist or is not available."); - } - } - } - - @Command( - aliases = { "sel" }, - usage = "", - desc = "Choose the snapshot based on the list id", - min = 1, - max = 1 - ) - @CommandPermissions("worldedit.snapshots.restore") - public void sel(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - LocalConfiguration config = we.getConfiguration(); - - if (config.snapshotRepo == null) { - player.printError("Snapshot/backup restore is not configured."); - return; - } - - int index = -1; - try { - index = Integer.parseInt(args.getString(0)); - } catch (NumberFormatException e) { - player.printError("Invalid index, " + args.getString(0) + " is not a valid integer."); - return; - } - - if (index < 1) { - player.printError("Invalid index, must be equal or higher then 1."); - return; - } - - try { - List snapshots = config.snapshotRepo.getSnapshots(true, player.getWorld().getName()); - if (snapshots.size() < index) { - player.printError("Invalid index, must be between 1 and " + snapshots.size() + "."); - return; - } - Snapshot snapshot = snapshots.get(index - 1); - if (snapshot == null) { - player.printError("That snapshot does not exist or is not available."); - return; - } - session.setSnapshot(snapshot); - player.print("Snapshot set to: " + snapshot.getName()); - } catch (MissingWorldException e) { - player.printError("No snapshots were found for this world."); - } - } - - @Command( - aliases = { "before" }, - usage = "", - desc = "Choose the nearest snapshot before a date", - min = 1, - max = -1 - ) - @CommandPermissions("worldedit.snapshots.restore") - public void before(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - LocalConfiguration config = we.getConfiguration(); - - if (config.snapshotRepo == null) { - player.printError("Snapshot/backup restore is not configured."); - return; - } - - Calendar date = session.detectDate(args.getJoinedStrings(0)); - - if (date == null) { - player.printError("Could not detect the date inputted."); - } else { - try { - Snapshot snapshot = config.snapshotRepo.getSnapshotBefore(date, player.getWorld().getName()); - - if (snapshot == null) { - dateFormat.setTimeZone(session.getTimeZone()); - player.printError("Couldn't find a snapshot before " - + dateFormat.format(date.getTime()) + "."); - } else { - session.setSnapshot(snapshot); - player.print("Snapshot set to: " + snapshot.getName()); - } - } catch (MissingWorldException ex) { - player.printError("No snapshots were found for this world."); - } - } - } - - @Command( - aliases = { "after" }, - usage = "", - desc = "Choose the nearest snapshot after a date", - min = 1, - max = -1 - ) - @CommandPermissions("worldedit.snapshots.restore") - public void after(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - LocalConfiguration config = we.getConfiguration(); - - if (config.snapshotRepo == null) { - player.printError("Snapshot/backup restore is not configured."); - return; - } - - Calendar date = session.detectDate(args.getJoinedStrings(0)); - - if (date == null) { - player.printError("Could not detect the date inputted."); - } else { - try { - Snapshot snapshot = config.snapshotRepo.getSnapshotAfter(date, player.getWorld().getName()); - if (snapshot == null) { - dateFormat.setTimeZone(session.getTimeZone()); - player.printError("Couldn't find a snapshot after " - + dateFormat.format(date.getTime()) + "."); - } else { - session.setSnapshot(snapshot); - player.print("Snapshot set to: " + snapshot.getName()); - } - } catch (MissingWorldException ex) { - player.printError("No snapshots were found for this world."); - } - } - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command; + +import java.io.File; +import java.io.IOException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.List; +import java.util.logging.Logger; +import com.sk89q.minecraft.util.commands.Command; +import com.sk89q.minecraft.util.commands.CommandContext; +import com.sk89q.minecraft.util.commands.CommandPermissions; +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.world.storage.MissingWorldException; +import com.sk89q.worldedit.world.snapshot.InvalidSnapshotException; +import com.sk89q.worldedit.world.snapshot.Snapshot; + +/** + * Snapshot commands. + * + * @author sk89q + */ +public class SnapshotCommands { + private static final Logger logger = Logger.getLogger("Minecraft.WorldEdit"); + private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); + + private final WorldEdit we; + + public SnapshotCommands(WorldEdit we) { + this.we = we; + } + + @Command( + aliases = { "list" }, + usage = "[num]", + desc = "List snapshots", + min = 0, + max = 1 + ) + @CommandPermissions("worldedit.snapshots.list") + public void list(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + LocalConfiguration config = we.getConfiguration(); + + if (config.snapshotRepo == null) { + player.printError("Snapshot/backup restore is not configured."); + return; + } + + try { + List snapshots = config.snapshotRepo.getSnapshots(true, player.getWorld().getName()); + + if (snapshots.size() > 0) { + + int num = args.argsLength() > 0 ? Math.min(40, Math.max(5, args.getInteger(0))) : 5; + + player.print("Snapshots for world: '" + player.getWorld().getName() + "'"); + for (byte i = 0; i < Math.min(num, snapshots.size()); i++) { + player.print((i + 1) + ". " + snapshots.get(i).getName()); + } + + player.print("Use /snap use [snapshot] or /snap use latest."); + } else { + player.printError("No snapshots are available. See console for details."); + + // Okay, let's toss some debugging information! + File dir = config.snapshotRepo.getDirectory(); + + try { + logger.info("WorldEdit found no snapshots: looked in: " + + dir.getCanonicalPath()); + } catch (IOException e) { + logger.info("WorldEdit found no snapshots: looked in " + + "(NON-RESOLVABLE PATH - does it exist?): " + + dir.getPath()); + } + } + } catch (MissingWorldException ex) { + player.printError("No snapshots were found for this world."); + } + } + + @Command( + aliases = { "use" }, + usage = "", + desc = "Choose a snapshot to use", + min = 1, + max = 1 + ) + @CommandPermissions("worldedit.snapshots.restore") + public void use(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + LocalConfiguration config = we.getConfiguration(); + + if (config.snapshotRepo == null) { + player.printError("Snapshot/backup restore is not configured."); + return; + } + + String name = args.getString(0); + + // Want the latest snapshot? + if (name.equalsIgnoreCase("latest")) { + try { + Snapshot snapshot = config.snapshotRepo.getDefaultSnapshot(player.getWorld().getName()); + + if (snapshot != null) { + session.setSnapshot(null); + player.print("Now using newest snapshot."); + } else { + player.printError("No snapshots were found."); + } + } catch (MissingWorldException ex) { + player.printError("No snapshots were found for this world."); + } + } else { + try { + session.setSnapshot(config.snapshotRepo.getSnapshot(name)); + player.print("Snapshot set to: " + name); + } catch (InvalidSnapshotException e) { + player.printError("That snapshot does not exist or is not available."); + } + } + } + + @Command( + aliases = { "sel" }, + usage = "", + desc = "Choose the snapshot based on the list id", + min = 1, + max = 1 + ) + @CommandPermissions("worldedit.snapshots.restore") + public void sel(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + LocalConfiguration config = we.getConfiguration(); + + if (config.snapshotRepo == null) { + player.printError("Snapshot/backup restore is not configured."); + return; + } + + int index = -1; + try { + index = Integer.parseInt(args.getString(0)); + } catch (NumberFormatException e) { + player.printError("Invalid index, " + args.getString(0) + " is not a valid integer."); + return; + } + + if (index < 1) { + player.printError("Invalid index, must be equal or higher then 1."); + return; + } + + try { + List snapshots = config.snapshotRepo.getSnapshots(true, player.getWorld().getName()); + if (snapshots.size() < index) { + player.printError("Invalid index, must be between 1 and " + snapshots.size() + "."); + return; + } + Snapshot snapshot = snapshots.get(index - 1); + if (snapshot == null) { + player.printError("That snapshot does not exist or is not available."); + return; + } + session.setSnapshot(snapshot); + player.print("Snapshot set to: " + snapshot.getName()); + } catch (MissingWorldException e) { + player.printError("No snapshots were found for this world."); + } + } + + @Command( + aliases = { "before" }, + usage = "", + desc = "Choose the nearest snapshot before a date", + min = 1, + max = -1 + ) + @CommandPermissions("worldedit.snapshots.restore") + public void before(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + LocalConfiguration config = we.getConfiguration(); + + if (config.snapshotRepo == null) { + player.printError("Snapshot/backup restore is not configured."); + return; + } + + Calendar date = session.detectDate(args.getJoinedStrings(0)); + + if (date == null) { + player.printError("Could not detect the date inputted."); + } else { + try { + Snapshot snapshot = config.snapshotRepo.getSnapshotBefore(date, player.getWorld().getName()); + + if (snapshot == null) { + dateFormat.setTimeZone(session.getTimeZone()); + player.printError("Couldn't find a snapshot before " + + dateFormat.format(date.getTime()) + "."); + } else { + session.setSnapshot(snapshot); + player.print("Snapshot set to: " + snapshot.getName()); + } + } catch (MissingWorldException ex) { + player.printError("No snapshots were found for this world."); + } + } + } + + @Command( + aliases = { "after" }, + usage = "", + desc = "Choose the nearest snapshot after a date", + min = 1, + max = -1 + ) + @CommandPermissions("worldedit.snapshots.restore") + public void after(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + LocalConfiguration config = we.getConfiguration(); + + if (config.snapshotRepo == null) { + player.printError("Snapshot/backup restore is not configured."); + return; + } + + Calendar date = session.detectDate(args.getJoinedStrings(0)); + + if (date == null) { + player.printError("Could not detect the date inputted."); + } else { + try { + Snapshot snapshot = config.snapshotRepo.getSnapshotAfter(date, player.getWorld().getName()); + if (snapshot == null) { + dateFormat.setTimeZone(session.getTimeZone()); + player.printError("Couldn't find a snapshot after " + + dateFormat.format(date.getTime()) + "."); + } else { + session.setSnapshot(snapshot); + player.print("Snapshot set to: " + snapshot.getName()); + } + } catch (MissingWorldException ex) { + player.printError("No snapshots were found for this world."); + } + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/commands/SnapshotUtilCommands.java b/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java similarity index 91% rename from src/main/java/com/sk89q/worldedit/commands/SnapshotUtilCommands.java rename to src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java index 7dde042b2..0332fb513 100644 --- a/src/main/java/com/sk89q/worldedit/commands/SnapshotUtilCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java @@ -1,169 +1,169 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.commands; - -import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION; - -import java.io.File; -import java.io.IOException; -import java.util.logging.Logger; - -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.Logging; -import com.sk89q.minecraft.util.commands.NestedCommand; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.LocalConfiguration; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.data.ChunkStore; -import com.sk89q.worldedit.data.DataException; -import com.sk89q.worldedit.data.MissingWorldException; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.snapshots.InvalidSnapshotException; -import com.sk89q.worldedit.snapshots.Snapshot; -import com.sk89q.worldedit.snapshots.SnapshotRestore; - -public class SnapshotUtilCommands { - - private static final Logger logger = Logger.getLogger("Minecraft.WorldEdit"); - - private final WorldEdit we; - - public SnapshotUtilCommands(WorldEdit we) { - this.we = we; - } - - @Command( - aliases = { "snapshot", "snap" }, - desc = "Snapshot commands" - ) - @NestedCommand(SnapshotCommands.class) - public void snapshot(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - } - - @Command( - aliases = { "restore", "/restore" }, - usage = "[snapshot]", - desc = "Restore the selection from a snapshot", - min = 0, - max = 1 - ) - @Logging(REGION) - @CommandPermissions("worldedit.snapshots.restore") - public void restore(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - LocalConfiguration config = we.getConfiguration(); - - if (config.snapshotRepo == null) { - player.printError("Snapshot/backup restore is not configured."); - return; - } - - Region region = session.getSelection(player.getWorld()); - Snapshot snapshot; - - if (args.argsLength() > 0) { - try { - snapshot = config.snapshotRepo.getSnapshot(args.getString(0)); - } catch (InvalidSnapshotException e) { - player.printError("That snapshot does not exist or is not available."); - return; - } - } else { - snapshot = session.getSnapshot(); - } - - // No snapshot set? - if (snapshot == null) { - try { - snapshot = config.snapshotRepo.getDefaultSnapshot(player.getWorld().getName()); - - if (snapshot == null) { - player.printError("No snapshots were found. See console for details."); - - // Okay, let's toss some debugging information! - File dir = config.snapshotRepo.getDirectory(); - - try { - logger.info("WorldEdit found no snapshots: looked in: " - + dir.getCanonicalPath()); - } catch (IOException e) { - logger.info("WorldEdit found no snapshots: looked in " - + "(NON-RESOLVABLE PATH - does it exist?): " - + dir.getPath()); - } - - return; - } - } catch (MissingWorldException ex) { - player.printError("No snapshots were found for this world."); - return; - } - } - - ChunkStore chunkStore = null; - - // Load chunk store - try { - chunkStore = snapshot.getChunkStore(); - player.print("Snapshot '" + snapshot.getName() + "' loaded; now restoring..."); - } catch (DataException e) { - player.printError("Failed to load snapshot: " + e.getMessage()); - return; - } catch (IOException e) { - player.printError("Failed to load snapshot: " + e.getMessage()); - return; - } - - try { - // Restore snapshot - SnapshotRestore restore = new SnapshotRestore(chunkStore, editSession, region); - //player.print(restore.getChunksAffected() + " chunk(s) will be loaded."); - - restore.restore(); - - if (restore.hadTotalFailure()) { - String error = restore.getLastErrorMessage(); - if (error != null) { - player.printError("Errors prevented any blocks from being restored."); - player.printError("Last error: " + error); - } else { - player.printError("No chunks could be loaded. (Bad archive?)"); - } - } else { - player.print(String.format("Restored; %d " - + "missing chunks and %d other errors.", - restore.getMissingChunks().size(), - restore.getErrorChunks().size())); - } - } finally { - try { - chunkStore.close(); - } catch (IOException e) { - } - } - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.command; + +import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION; + +import java.io.File; +import java.io.IOException; +import java.util.logging.Logger; + +import com.sk89q.minecraft.util.commands.Command; +import com.sk89q.minecraft.util.commands.CommandContext; +import com.sk89q.minecraft.util.commands.CommandPermissions; +import com.sk89q.minecraft.util.commands.Logging; +import com.sk89q.minecraft.util.commands.NestedCommand; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.world.storage.ChunkStore; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.storage.MissingWorldException; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.snapshot.InvalidSnapshotException; +import com.sk89q.worldedit.world.snapshot.Snapshot; +import com.sk89q.worldedit.world.snapshot.SnapshotRestore; + +public class SnapshotUtilCommands { + + private static final Logger logger = Logger.getLogger("Minecraft.WorldEdit"); + + private final WorldEdit we; + + public SnapshotUtilCommands(WorldEdit we) { + this.we = we; + } + + @Command( + aliases = { "snapshot", "snap" }, + desc = "Snapshot commands" + ) + @NestedCommand(SnapshotCommands.class) + public void snapshot(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + } + + @Command( + aliases = { "restore", "/restore" }, + usage = "[snapshot]", + desc = "Restore the selection from a snapshot", + min = 0, + max = 1 + ) + @Logging(REGION) + @CommandPermissions("worldedit.snapshots.restore") + public void restore(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + LocalConfiguration config = we.getConfiguration(); + + if (config.snapshotRepo == null) { + player.printError("Snapshot/backup restore is not configured."); + return; + } + + Region region = session.getSelection(player.getWorld()); + Snapshot snapshot; + + if (args.argsLength() > 0) { + try { + snapshot = config.snapshotRepo.getSnapshot(args.getString(0)); + } catch (InvalidSnapshotException e) { + player.printError("That snapshot does not exist or is not available."); + return; + } + } else { + snapshot = session.getSnapshot(); + } + + // No snapshot set? + if (snapshot == null) { + try { + snapshot = config.snapshotRepo.getDefaultSnapshot(player.getWorld().getName()); + + if (snapshot == null) { + player.printError("No snapshots were found. See console for details."); + + // Okay, let's toss some debugging information! + File dir = config.snapshotRepo.getDirectory(); + + try { + logger.info("WorldEdit found no snapshots: looked in: " + + dir.getCanonicalPath()); + } catch (IOException e) { + logger.info("WorldEdit found no snapshots: looked in " + + "(NON-RESOLVABLE PATH - does it exist?): " + + dir.getPath()); + } + + return; + } + } catch (MissingWorldException ex) { + player.printError("No snapshots were found for this world."); + return; + } + } + + ChunkStore chunkStore = null; + + // Load chunk store + try { + chunkStore = snapshot.getChunkStore(); + player.print("Snapshot '" + snapshot.getName() + "' loaded; now restoring..."); + } catch (DataException e) { + player.printError("Failed to load snapshot: " + e.getMessage()); + return; + } catch (IOException e) { + player.printError("Failed to load snapshot: " + e.getMessage()); + return; + } + + try { + // Restore snapshot + SnapshotRestore restore = new SnapshotRestore(chunkStore, editSession, region); + //player.print(restore.getChunksAffected() + " chunk(s) will be loaded."); + + restore.restore(); + + if (restore.hadTotalFailure()) { + String error = restore.getLastErrorMessage(); + if (error != null) { + player.printError("Errors prevented any blocks from being restored."); + player.printError("Last error: " + error); + } else { + player.printError("No chunks could be loaded. (Bad archive?)"); + } + } else { + player.print(String.format("Restored; %d " + + "missing chunks and %d other errors.", + restore.getMissingChunks().size(), + restore.getErrorChunks().size())); + } + } finally { + try { + chunkStore.close(); + } catch (IOException e) { + } + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/commands/SuperPickaxeCommands.java b/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java similarity index 92% rename from src/main/java/com/sk89q/worldedit/commands/SuperPickaxeCommands.java rename to src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java index 141bc27e3..29af51931 100644 --- a/src/main/java/com/sk89q/worldedit/commands/SuperPickaxeCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java @@ -1,105 +1,105 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.commands; - -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.LocalConfiguration; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.tools.AreaPickaxe; -import com.sk89q.worldedit.tools.RecursivePickaxe; -import com.sk89q.worldedit.tools.SinglePickaxe; - -public class SuperPickaxeCommands { - private final WorldEdit we; - - public SuperPickaxeCommands(WorldEdit we) { - this.we = we; - } - - @Command( - aliases = { "single" }, - usage = "", - desc = "Enable the single block super pickaxe mode", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.superpickaxe") - public void single(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - session.setSuperPickaxe(new SinglePickaxe()); - session.enableSuperPickAxe(); - player.print("Mode changed. Left click with a pickaxe. // to disable."); - } - - @Command( - aliases = { "area" }, - usage = "", - desc = "Enable the area super pickaxe pickaxe mode", - min = 1, - max = 1 - ) - @CommandPermissions("worldedit.superpickaxe.area") - public void area(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - LocalConfiguration config = we.getConfiguration(); - int range = args.getInteger(0); - - if (range > config.maxSuperPickaxeSize) { - player.printError("Maximum range: " + config.maxSuperPickaxeSize); - return; - } - - session.setSuperPickaxe(new AreaPickaxe(range)); - session.enableSuperPickAxe(); - player.print("Mode changed. Left click with a pickaxe. // to disable."); - } - - @Command( - aliases = { "recur", "recursive" }, - usage = "", - desc = "Enable the recursive super pickaxe pickaxe mode", - min = 1, - max = 1 - ) - @CommandPermissions("worldedit.superpickaxe.recursive") - public void recursive(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - LocalConfiguration config = we.getConfiguration(); - double range = args.getDouble(0); - - if (range > config.maxSuperPickaxeSize) { - player.printError("Maximum range: " + config.maxSuperPickaxeSize); - return; - } - - session.setSuperPickaxe(new RecursivePickaxe(range)); - session.enableSuperPickAxe(); - player.print("Mode changed. Left click with a pickaxe. // to disable."); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.command; + +import com.sk89q.minecraft.util.commands.Command; +import com.sk89q.minecraft.util.commands.CommandContext; +import com.sk89q.minecraft.util.commands.CommandPermissions; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.tool.AreaPickaxe; +import com.sk89q.worldedit.command.tool.RecursivePickaxe; +import com.sk89q.worldedit.command.tool.SinglePickaxe; + +public class SuperPickaxeCommands { + private final WorldEdit we; + + public SuperPickaxeCommands(WorldEdit we) { + this.we = we; + } + + @Command( + aliases = { "single" }, + usage = "", + desc = "Enable the single block super pickaxe mode", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.superpickaxe") + public void single(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + session.setSuperPickaxe(new SinglePickaxe()); + session.enableSuperPickAxe(); + player.print("Mode changed. Left click with a pickaxe. // to disable."); + } + + @Command( + aliases = { "area" }, + usage = "", + desc = "Enable the area super pickaxe pickaxe mode", + min = 1, + max = 1 + ) + @CommandPermissions("worldedit.superpickaxe.area") + public void area(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + LocalConfiguration config = we.getConfiguration(); + int range = args.getInteger(0); + + if (range > config.maxSuperPickaxeSize) { + player.printError("Maximum range: " + config.maxSuperPickaxeSize); + return; + } + + session.setSuperPickaxe(new AreaPickaxe(range)); + session.enableSuperPickAxe(); + player.print("Mode changed. Left click with a pickaxe. // to disable."); + } + + @Command( + aliases = { "recur", "recursive" }, + usage = "", + desc = "Enable the recursive super pickaxe pickaxe mode", + min = 1, + max = 1 + ) + @CommandPermissions("worldedit.superpickaxe.recursive") + public void recursive(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + LocalConfiguration config = we.getConfiguration(); + double range = args.getDouble(0); + + if (range > config.maxSuperPickaxeSize) { + player.printError("Maximum range: " + config.maxSuperPickaxeSize); + return; + } + + session.setSuperPickaxe(new RecursivePickaxe(range)); + session.enableSuperPickAxe(); + player.print("Mode changed. Left click with a pickaxe. // to disable."); + } +} diff --git a/src/main/java/com/sk89q/worldedit/commands/ToolCommands.java b/src/main/java/com/sk89q/worldedit/command/ToolCommands.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/commands/ToolCommands.java rename to src/main/java/com/sk89q/worldedit/command/ToolCommands.java index c3e3662d8..2b5fb4b22 100644 --- a/src/main/java/com/sk89q/worldedit/commands/ToolCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/ToolCommands.java @@ -1,212 +1,212 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.commands; - -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.NestedCommand; -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.blocks.ItemType; -import com.sk89q.worldedit.patterns.Pattern; -import com.sk89q.worldedit.tools.*; -import com.sk89q.worldedit.util.TreeGenerator; - -public class ToolCommands { - private final WorldEdit we; - - public ToolCommands(WorldEdit we) { - this.we = we; - } - - @Command( - aliases = { "none" }, - usage = "", - desc = "Unbind a bound tool from your current item", - min = 0, - max = 0 - ) - public void none(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - session.setTool(player.getItemInHand(), null); - player.print("Tool unbound from your current item."); - } - - @Command( - aliases = { "info" }, - usage = "", - desc = "Block information tool", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.tool.info") - public void info(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - session.setTool(player.getItemInHand(), new QueryTool()); - player.print("Info tool bound to " - + ItemType.toHeldName(player.getItemInHand()) + "."); - } - - @Command( - aliases = { "tree" }, - usage = "[type]", - desc = "Tree generator tool", - min = 0, - max = 1 - ) - @CommandPermissions("worldedit.tool.tree") - @SuppressWarnings("deprecation") - public void tree(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - TreeGenerator.TreeType type = args.argsLength() > 0 ? - type = TreeGenerator.lookup(args.getString(0)) - : TreeGenerator.TreeType.TREE; - - if (type == null) { - player.printError("Tree type '" + args.getString(0) + "' is unknown."); - return; - } - - session.setTool(player.getItemInHand(), new TreePlanter(new TreeGenerator(type))); - player.print("Tree tool bound to " - + ItemType.toHeldName(player.getItemInHand()) + "."); - } - - @Command( - aliases = { "repl" }, - usage = "", - desc = "Block replacer tool", - min = 1, - max = 1 - ) - @CommandPermissions("worldedit.tool.replacer") - public void repl(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - BaseBlock targetBlock = we.getBlock(player, args.getString(0)); - session.setTool(player.getItemInHand(), new BlockReplacer(targetBlock)); - player.print("Block replacer tool bound to " - + ItemType.toHeldName(player.getItemInHand()) + "."); - } - - @Command( - aliases = { "cycler" }, - usage = "", - desc = "Block data cycler tool", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.tool.data-cycler") - public void cycler(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - session.setTool(player.getItemInHand(), new BlockDataCyler()); - player.print("Block data cycler tool bound to " - + ItemType.toHeldName(player.getItemInHand()) + "."); - } - - @Command( - aliases = { "floodfill", "flood" }, - usage = " ", - desc = "Flood fill tool", - min = 2, - max = 2 - ) - @CommandPermissions("worldedit.tool.flood-fill") - public void floodFill(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - LocalConfiguration config = we.getConfiguration(); - int range = args.getInteger(1); - - if (range > config.maxSuperPickaxeSize) { - player.printError("Maximum range: " + config.maxSuperPickaxeSize); - return; - } - - Pattern pattern = we.getBlockPattern(player, args.getString(0)); - session.setTool(player.getItemInHand(), new FloodFillTool(range, pattern)); - player.print("Block flood fill tool bound to " - + ItemType.toHeldName(player.getItemInHand()) + "."); - } - - @Command( - aliases = { "brush", "br" }, - desc = "Brush tool" - ) - @NestedCommand(BrushCommands.class) - public void brush(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - } - - @Command( - aliases = { "deltree" }, - usage = "", - desc = "Floating tree remover tool", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.tool.deltree") - public void deltree(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - session.setTool(player.getItemInHand(), new FloatingTreeRemover()); - player.print("Floating tree remover tool bound to " - + ItemType.toHeldName(player.getItemInHand()) + "."); - } - - @Command( - aliases = { "farwand" }, - usage = "", - desc = "Wand at a distance tool", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.tool.farwand") - public void farwand(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - session.setTool(player.getItemInHand(), new DistanceWand()); - player.print("Far wand tool bound to " + ItemType.toHeldName(player.getItemInHand()) + "."); - } - - @Command( - aliases = { "lrbuild", "/lrbuild" }, - usage = " ", - desc = "Long-range building tool", - min = 2, - max = 2 - ) - @CommandPermissions("worldedit.tool.lrbuild") - public void longrangebuildtool(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - BaseBlock secondary = we.getBlock(player, args.getString(0)); - BaseBlock primary = we.getBlock(player, args.getString(1)); - session.setTool(player.getItemInHand(), new LongRangeBuildTool(primary, secondary)); - player.print("Long-range building tool bound to " + ItemType.toHeldName(player.getItemInHand()) + "."); - player.print("Left-click set to " + ItemType.toName(secondary.getType()) + "; right-click set to " - + ItemType.toName(primary.getType()) + "."); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.command; + +import com.sk89q.minecraft.util.commands.Command; +import com.sk89q.minecraft.util.commands.CommandContext; +import com.sk89q.minecraft.util.commands.CommandPermissions; +import com.sk89q.minecraft.util.commands.NestedCommand; +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.ItemType; +import com.sk89q.worldedit.patterns.Pattern; +import com.sk89q.worldedit.command.tool.*; +import com.sk89q.worldedit.util.TreeGenerator; + +public class ToolCommands { + private final WorldEdit we; + + public ToolCommands(WorldEdit we) { + this.we = we; + } + + @Command( + aliases = { "none" }, + usage = "", + desc = "Unbind a bound tool from your current item", + min = 0, + max = 0 + ) + public void none(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + session.setTool(player.getItemInHand(), null); + player.print("Tool unbound from your current item."); + } + + @Command( + aliases = { "info" }, + usage = "", + desc = "Block information tool", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.tool.info") + public void info(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + session.setTool(player.getItemInHand(), new QueryTool()); + player.print("Info tool bound to " + + ItemType.toHeldName(player.getItemInHand()) + "."); + } + + @Command( + aliases = { "tree" }, + usage = "[type]", + desc = "Tree generator tool", + min = 0, + max = 1 + ) + @CommandPermissions("worldedit.tool.tree") + @SuppressWarnings("deprecation") + public void tree(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + TreeGenerator.TreeType type = args.argsLength() > 0 ? + type = TreeGenerator.lookup(args.getString(0)) + : TreeGenerator.TreeType.TREE; + + if (type == null) { + player.printError("Tree type '" + args.getString(0) + "' is unknown."); + return; + } + + session.setTool(player.getItemInHand(), new TreePlanter(new TreeGenerator(type))); + player.print("Tree tool bound to " + + ItemType.toHeldName(player.getItemInHand()) + "."); + } + + @Command( + aliases = { "repl" }, + usage = "", + desc = "Block replacer tool", + min = 1, + max = 1 + ) + @CommandPermissions("worldedit.tool.replacer") + public void repl(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + BaseBlock targetBlock = we.getBlock(player, args.getString(0)); + session.setTool(player.getItemInHand(), new BlockReplacer(targetBlock)); + player.print("Block replacer tool bound to " + + ItemType.toHeldName(player.getItemInHand()) + "."); + } + + @Command( + aliases = { "cycler" }, + usage = "", + desc = "Block data cycler tool", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.tool.data-cycler") + public void cycler(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + session.setTool(player.getItemInHand(), new BlockDataCyler()); + player.print("Block data cycler tool bound to " + + ItemType.toHeldName(player.getItemInHand()) + "."); + } + + @Command( + aliases = { "floodfill", "flood" }, + usage = " ", + desc = "Flood fill tool", + min = 2, + max = 2 + ) + @CommandPermissions("worldedit.tool.flood-fill") + public void floodFill(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + LocalConfiguration config = we.getConfiguration(); + int range = args.getInteger(1); + + if (range > config.maxSuperPickaxeSize) { + player.printError("Maximum range: " + config.maxSuperPickaxeSize); + return; + } + + Pattern pattern = we.getBlockPattern(player, args.getString(0)); + session.setTool(player.getItemInHand(), new FloodFillTool(range, pattern)); + player.print("Block flood fill tool bound to " + + ItemType.toHeldName(player.getItemInHand()) + "."); + } + + @Command( + aliases = { "brush", "br" }, + desc = "Brush tool" + ) + @NestedCommand(BrushCommands.class) + public void brush(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + } + + @Command( + aliases = { "deltree" }, + usage = "", + desc = "Floating tree remover tool", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.tool.deltree") + public void deltree(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + session.setTool(player.getItemInHand(), new FloatingTreeRemover()); + player.print("Floating tree remover tool bound to " + + ItemType.toHeldName(player.getItemInHand()) + "."); + } + + @Command( + aliases = { "farwand" }, + usage = "", + desc = "Wand at a distance tool", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.tool.farwand") + public void farwand(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + session.setTool(player.getItemInHand(), new DistanceWand()); + player.print("Far wand tool bound to " + ItemType.toHeldName(player.getItemInHand()) + "."); + } + + @Command( + aliases = { "lrbuild", "/lrbuild" }, + usage = " ", + desc = "Long-range building tool", + min = 2, + max = 2 + ) + @CommandPermissions("worldedit.tool.lrbuild") + public void longrangebuildtool(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + BaseBlock secondary = we.getBlock(player, args.getString(0)); + BaseBlock primary = we.getBlock(player, args.getString(1)); + session.setTool(player.getItemInHand(), new LongRangeBuildTool(primary, secondary)); + player.print("Long-range building tool bound to " + ItemType.toHeldName(player.getItemInHand()) + "."); + player.print("Left-click set to " + ItemType.toName(secondary.getType()) + "; right-click set to " + + ItemType.toName(primary.getType()) + "."); + } +} diff --git a/src/main/java/com/sk89q/worldedit/commands/ToolUtilCommands.java b/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/commands/ToolUtilCommands.java rename to src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java index 18ed67f9a..9385a3767 100644 --- a/src/main/java/com/sk89q/worldedit/commands/ToolUtilCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java @@ -1,158 +1,158 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.commands; - -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.NestedCommand; -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.masks.Mask; -import com.sk89q.worldedit.patterns.Pattern; - -/** - * Tool commands. - * - * @author sk89q - */ -public class ToolUtilCommands { - private final WorldEdit we; - - public ToolUtilCommands(WorldEdit we) { - this.we = we; - } - - @Command( - aliases = { "/", "," }, - usage = "[on|off]", - desc = "Toggle the super pickaxe pickaxe function", - min = 0, - max = 1 - ) - @CommandPermissions("worldedit.superpickaxe") - public void togglePickaxe(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - String newState = args.getString(0, null); - if (session.hasSuperPickAxe()) { - if ("on".equals(newState)) { - player.printError("Super pick axe already enabled."); - return; - } - - session.disableSuperPickAxe(); - player.print("Super pick axe disabled."); - } else { - if ("off".equals(newState)) { - player.printError("Super pick axe already disabled."); - return; - } - session.enableSuperPickAxe(); - player.print("Super pick axe enabled."); - } - - } - - @Command( - aliases = { "superpickaxe", "pickaxe", "sp" }, - desc = "Select super pickaxe mode" - ) - @NestedCommand(SuperPickaxeCommands.class) - public void pickaxe(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - } - - @Command( - aliases = {"tool"}, - desc = "Select a tool to bind" - ) - @NestedCommand(ToolCommands.class) - public void tool(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - } - - @Command( - aliases = { "mask" }, - usage = "[mask]", - desc = "Set the brush mask", - min = 0, - max = -1 - ) - @CommandPermissions("worldedit.brush.options.mask") - public void mask(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - if (args.argsLength() == 0) { - session.getBrushTool(player.getItemInHand()).setMask(null); - player.print("Brush mask disabled."); - } else { - Mask mask = we.getBlockMask(player, session, args.getJoinedStrings(0)); - session.getBrushTool(player.getItemInHand()).setMask(mask); - player.print("Brush mask set."); - } - } - - @Command( - aliases = { "mat", "material" }, - usage = "[pattern]", - desc = "Set the brush material", - min = 1, - max = 1 - ) - @CommandPermissions("worldedit.brush.options.material") - public void material(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - Pattern pattern = we.getBlockPattern(player, args.getString(0)); - session.getBrushTool(player.getItemInHand()).setFill(pattern); - player.print("Brush material set."); - } - - @Command( - aliases = { "range" }, - usage = "[pattern]", - desc = "Set the brush range", - min = 1, - max = 1 - ) - @CommandPermissions("worldedit.brush.options.range") - public void range(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - int range = args.getInteger(0); - session.getBrushTool(player.getItemInHand()).setRange(range); - player.print("Brush range set."); - } - - @Command( - aliases = { "size" }, - usage = "[pattern]", - desc = "Set the brush size", - min = 1, - max = 1 - ) - @CommandPermissions("worldedit.brush.options.size") - public void size(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - int radius = args.getInteger(0); - we.checkMaxBrushRadius(radius); - - session.getBrushTool(player.getItemInHand()).setSize(radius); - player.print("Brush size set."); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command; + +import com.sk89q.minecraft.util.commands.Command; +import com.sk89q.minecraft.util.commands.CommandContext; +import com.sk89q.minecraft.util.commands.CommandPermissions; +import com.sk89q.minecraft.util.commands.NestedCommand; +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.masks.Mask; +import com.sk89q.worldedit.patterns.Pattern; + +/** + * Tool commands. + * + * @author sk89q + */ +public class ToolUtilCommands { + private final WorldEdit we; + + public ToolUtilCommands(WorldEdit we) { + this.we = we; + } + + @Command( + aliases = { "/", "," }, + usage = "[on|off]", + desc = "Toggle the super pickaxe pickaxe function", + min = 0, + max = 1 + ) + @CommandPermissions("worldedit.superpickaxe") + public void togglePickaxe(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + String newState = args.getString(0, null); + if (session.hasSuperPickAxe()) { + if ("on".equals(newState)) { + player.printError("Super pick axe already enabled."); + return; + } + + session.disableSuperPickAxe(); + player.print("Super pick axe disabled."); + } else { + if ("off".equals(newState)) { + player.printError("Super pick axe already disabled."); + return; + } + session.enableSuperPickAxe(); + player.print("Super pick axe enabled."); + } + + } + + @Command( + aliases = { "superpickaxe", "pickaxe", "sp" }, + desc = "Select super pickaxe mode" + ) + @NestedCommand(SuperPickaxeCommands.class) + public void pickaxe(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + } + + @Command( + aliases = {"tool"}, + desc = "Select a tool to bind" + ) + @NestedCommand(ToolCommands.class) + public void tool(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + } + + @Command( + aliases = { "mask" }, + usage = "[mask]", + desc = "Set the brush mask", + min = 0, + max = -1 + ) + @CommandPermissions("worldedit.brush.options.mask") + public void mask(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + if (args.argsLength() == 0) { + session.getBrushTool(player.getItemInHand()).setMask(null); + player.print("Brush mask disabled."); + } else { + Mask mask = we.getBlockMask(player, session, args.getJoinedStrings(0)); + session.getBrushTool(player.getItemInHand()).setMask(mask); + player.print("Brush mask set."); + } + } + + @Command( + aliases = { "mat", "material" }, + usage = "[pattern]", + desc = "Set the brush material", + min = 1, + max = 1 + ) + @CommandPermissions("worldedit.brush.options.material") + public void material(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + Pattern pattern = we.getBlockPattern(player, args.getString(0)); + session.getBrushTool(player.getItemInHand()).setFill(pattern); + player.print("Brush material set."); + } + + @Command( + aliases = { "range" }, + usage = "[pattern]", + desc = "Set the brush range", + min = 1, + max = 1 + ) + @CommandPermissions("worldedit.brush.options.range") + public void range(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + int range = args.getInteger(0); + session.getBrushTool(player.getItemInHand()).setRange(range); + player.print("Brush range set."); + } + + @Command( + aliases = { "size" }, + usage = "[pattern]", + desc = "Set the brush size", + min = 1, + max = 1 + ) + @CommandPermissions("worldedit.brush.options.size") + public void size(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + int radius = args.getInteger(0); + we.checkMaxBrushRadius(radius); + + session.getBrushTool(player.getItemInHand()).setSize(radius); + player.print("Brush size set."); + } +} diff --git a/src/main/java/com/sk89q/worldedit/commands/UtilityCommands.java b/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java similarity index 97% rename from src/main/java/com/sk89q/worldedit/commands/UtilityCommands.java rename to src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index 12b88fbf6..9ca9c6533 100644 --- a/src/main/java/com/sk89q/worldedit/commands/UtilityCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -1,554 +1,554 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.commands; - -import com.sk89q.minecraft.util.commands.*; -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.LocalWorld.KillFlags; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.patterns.Pattern; -import com.sk89q.worldedit.patterns.SingleBlockPattern; -import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.regions.Region; - -import java.util.Comparator; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; - -import static com.sk89q.minecraft.util.commands.Logging.LogMode.PLACEMENT; - -/** - * Utility commands. - * - * @author sk89q - */ -public class UtilityCommands { - private final WorldEdit we; - - public UtilityCommands(WorldEdit we) { - this.we = we; - } - - @Command( - aliases = { "/fill" }, - usage = " [depth]", - desc = "Fill a hole", - min = 2, - max = 3 - ) - @CommandPermissions("worldedit.fill") - @Logging(PLACEMENT) - public void fill(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - Pattern pattern = we.getBlockPattern(player, args.getString(0)); - double radius = Math.max(1, args.getDouble(1)); - we.checkMaxRadius(radius); - int depth = args.argsLength() > 2 ? Math.max(1, args.getInteger(2)) : 1; - - Vector pos = session.getPlacementPosition(player); - int affected = 0; - if (pattern instanceof SingleBlockPattern) { - affected = editSession.fillXZ(pos, - ((SingleBlockPattern) pattern).getBlock(), - radius, depth, false); - } else { - affected = editSession.fillXZ(pos, pattern, radius, depth, false); - } - player.print(affected + " block(s) have been created."); - } - - @Command( - aliases = { "/fillr" }, - usage = " [depth]", - desc = "Fill a hole recursively", - min = 2, - max = 3 - ) - @CommandPermissions("worldedit.fill.recursive") - @Logging(PLACEMENT) - public void fillr(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - Pattern pattern = we.getBlockPattern(player, args.getString(0)); - double radius = Math.max(1, args.getDouble(1)); - we.checkMaxRadius(radius); - int depth = args.argsLength() > 2 ? Math.max(1, args.getInteger(2)) : 1; - - Vector pos = session.getPlacementPosition(player); - int affected = 0; - if (pattern instanceof SingleBlockPattern) { - affected = editSession.fillXZ(pos, - ((SingleBlockPattern) pattern).getBlock(), - radius, depth, true); - } else { - affected = editSession.fillXZ(pos, pattern, radius, depth, true); - } - player.print(affected + " block(s) have been created."); - } - - @Command( - aliases = { "/drain" }, - usage = "", - desc = "Drain a pool", - min = 1, - max = 1 - ) - @CommandPermissions("worldedit.drain") - @Logging(PLACEMENT) - public void drain(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - double radius = Math.max(0, args.getDouble(0)); - we.checkMaxRadius(radius); - int affected = editSession.drainArea( - session.getPlacementPosition(player), radius); - player.print(affected + " block(s) have been changed."); - } - - @Command( - aliases = { "/fixlava", "fixlava" }, - usage = "", - desc = "Fix lava to be stationary", - min = 1, - max = 1 - ) - @CommandPermissions("worldedit.fixlava") - @Logging(PLACEMENT) - public void fixLava(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - double radius = Math.max(0, args.getDouble(0)); - we.checkMaxRadius(radius); - int affected = editSession.fixLiquid( - session.getPlacementPosition(player), radius, 10, 11); - player.print(affected + " block(s) have been changed."); - } - - @Command( - aliases = { "/fixwater", "fixwater" }, - usage = "", - desc = "Fix water to be stationary", - min = 1, - max = 1 - ) - @CommandPermissions("worldedit.fixwater") - @Logging(PLACEMENT) - public void fixWater(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - double radius = Math.max(0, args.getDouble(0)); - we.checkMaxRadius(radius); - int affected = editSession.fixLiquid( - session.getPlacementPosition(player), radius, 8, 9); - player.print(affected + " block(s) have been changed."); - } - - @Command( - aliases = { "/removeabove", "removeabove" }, - usage = "[size] [height]", - desc = "Remove blocks above your head.", - min = 0, - max = 2 - ) - @CommandPermissions("worldedit.removeabove") - @Logging(PLACEMENT) - public void removeAbove(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 1; - we.checkMaxRadius(size); - LocalWorld world = player.getWorld(); - int height = args.argsLength() > 1 ? Math.min((world.getMaxY() + 1), args.getInteger(1) + 2) : (world.getMaxY() + 1); - - int affected = editSession.removeAbove( - session.getPlacementPosition(player), size, height); - player.print(affected + " block(s) have been removed."); - } - - @Command( - aliases = { "/removebelow", "removebelow" }, - usage = "[size] [height]", - desc = "Remove blocks below you.", - min = 0, - max = 2 - ) - @CommandPermissions("worldedit.removebelow") - @Logging(PLACEMENT) - public void removeBelow(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 1; - we.checkMaxRadius(size); - LocalWorld world = player.getWorld(); - int height = args.argsLength() > 1 ? Math.min((world.getMaxY() + 1), args.getInteger(1) + 2) : (world.getMaxY() + 1); - - int affected = editSession.removeBelow(session.getPlacementPosition(player), size, height); - player.print(affected + " block(s) have been removed."); - } - - @Command( - aliases = { "/removenear", "removenear" }, - usage = " [size]", - desc = "Remove blocks near you.", - min = 1, - max = 2 - ) - @CommandPermissions("worldedit.removenear") - @Logging(PLACEMENT) - public void removeNear(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - BaseBlock block = we.getBlock(player, args.getString(0), true); - int size = Math.max(1, args.getInteger(1, 50)); - we.checkMaxRadius(size); - - int affected = editSession.removeNear(session.getPlacementPosition(player), block.getType(), size); - player.print(affected + " block(s) have been removed."); - } - - @Command( - aliases = { "/replacenear", "replacenear" }, - usage = " ", - desc = "Replace nearby blocks", - flags = "f", - min = 3, - max = 3 - ) - @CommandPermissions("worldedit.replacenear") - @Logging(PLACEMENT) - public void replaceNear(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - int size = Math.max(1, args.getInteger(0)); - int affected; - Set from; - Pattern to; - if (args.argsLength() == 2) { - from = null; - to = we.getBlockPattern(player, args.getString(1)); - } else { - from = we.getBlocks(player, args.getString(1), true, !args.hasFlag('f')); - to = we.getBlockPattern(player, args.getString(2)); - } - - Vector base = session.getPlacementPosition(player); - Vector min = base.subtract(size, size, size); - Vector max = base.add(size, size, size); - Region region = new CuboidRegion(player.getWorld(), min, max); - - if (to instanceof SingleBlockPattern) { - affected = editSession.replaceBlocks(region, from, ((SingleBlockPattern) to).getBlock()); - } else { - affected = editSession.replaceBlocks(region, from, to); - } - player.print(affected + " block(s) have been replaced."); - } - - @Command( - aliases = { "/snow", "snow" }, - usage = "[radius]", - desc = "Simulates snow", - min = 0, - max = 1 - ) - @CommandPermissions("worldedit.snow") - @Logging(PLACEMENT) - public void snow(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - double size = args.argsLength() > 0 ? Math.max(1, args.getDouble(0)) : 10; - - int affected = editSession.simulateSnow(session.getPlacementPosition(player), size); - player.print(affected + " surfaces covered. Let it snow~"); - } - - @Command( - aliases = {"/thaw", "thaw"}, - usage = "[radius]", - desc = "Thaws the area", - min = 0, - max = 1 - ) - @CommandPermissions("worldedit.thaw") - @Logging(PLACEMENT) - public void thaw(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - double size = args.argsLength() > 0 ? Math.max(1, args.getDouble(0)) : 10; - - int affected = editSession.thaw(session.getPlacementPosition(player), size); - player.print(affected + " surfaces thawed."); - } - - @Command( - aliases = { "/green", "green" }, - usage = "[radius]", - desc = "Greens the area", - flags = "f", - min = 0, - max = 1 - ) - @CommandPermissions("worldedit.green") - @Logging(PLACEMENT) - public void green(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - final double size = args.argsLength() > 0 ? Math.max(1, args.getDouble(0)) : 10; - final boolean onlyNormalDirt = !args.hasFlag('f'); - - final int affected = editSession.green(session.getPlacementPosition(player), size, onlyNormalDirt); - player.print(affected + " surfaces greened."); - } - - @Command( - aliases = { "/ex", "/ext", "/extinguish", "ex", "ext", "extinguish" }, - usage = "[radius]", - desc = "Extinguish nearby fire", - min = 0, - max = 1 - ) - @CommandPermissions("worldedit.extinguish") - @Logging(PLACEMENT) - public void extinguish(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - LocalConfiguration config = we.getConfiguration(); - - int defaultRadius = config.maxRadius != -1 ? Math.min(40, config.maxRadius) : 40; - int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) - : defaultRadius; - we.checkMaxRadius(size); - - int affected = editSession.removeNear(session.getPlacementPosition(player), 51, size); - player.print(affected + " block(s) have been removed."); - } - - @Command( - aliases = { "butcher" }, - usage = "[radius]", - flags = "plangbf", - desc = "Kill all or nearby mobs", - help = - "Kills nearby mobs, based on radius, if none is given uses default in configuration.\n" + - "Flags:" + - " -p also kills pets.\n" + - " -n also kills NPCs.\n" + - " -g also kills Golems.\n" + - " -a also kills animals.\n" + - " -b also kills ambient mobs.\n" + - " -f compounds all previous flags.\n" + - " -l strikes lightning on each killed mob.", - min = 0, - max = 1 - ) - @CommandPermissions("worldedit.butcher") - @Logging(PLACEMENT) - @Console - public void butcher(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - LocalConfiguration config = we.getConfiguration(); - - // technically the default can be larger than the max, but that's not my problem - int radius = config.butcherDefaultRadius; - - // there might be a better way to do this but my brain is fried right now - if (args.argsLength() > 0) { // user inputted radius, override the default - radius = args.getInteger(0); - if (config.butcherMaxRadius != -1) { // clamp if there is a max - if (radius == -1) { - radius = config.butcherMaxRadius; - } else { // Math.min does not work if radius is -1 (actually highest possible value) - radius = Math.min(radius, config.butcherMaxRadius); - } - } - } - - FlagContainer flags = new FlagContainer(player); - flags.or(KillFlags.FRIENDLY , args.hasFlag('f')); // No permission check here. Flags will instead be filtered by the subsequent calls. - flags.or(KillFlags.PETS , args.hasFlag('p'), "worldedit.butcher.pets"); - flags.or(KillFlags.NPCS , args.hasFlag('n'), "worldedit.butcher.npcs"); - flags.or(KillFlags.GOLEMS , args.hasFlag('g'), "worldedit.butcher.golems"); - flags.or(KillFlags.ANIMALS , args.hasFlag('a'), "worldedit.butcher.animals"); - flags.or(KillFlags.AMBIENT , args.hasFlag('b'), "worldedit.butcher.ambient"); - flags.or(KillFlags.WITH_LIGHTNING, args.hasFlag('l'), "worldedit.butcher.lightning"); - // If you add flags here, please add them to com.sk89q.worldedit.commands.BrushCommands.butcherBrush() as well - - int killed; - if (player.isPlayer()) { - killed = player.getWorld().killMobs(session.getPlacementPosition(player), radius, flags.flags); - } else { - killed = 0; - for (LocalWorld world : we.getServer().getWorlds()) { - killed += world.killMobs(new Vector(), radius, flags.flags); - } - } - - if (radius < 0) { - player.print("Killed " + killed + " mobs."); - } else { - player.print("Killed " + killed + " mobs in a radius of " + radius + "."); - } - } - - public static class FlagContainer { - private final LocalPlayer player; - public int flags = 0; - public FlagContainer(LocalPlayer player) { - this.player = player; - } - - public void or(int flag, boolean on) { - if (on) flags |= flag; - } - - public void or(int flag, boolean on, String permission) { - or(flag, on); - - if ((flags & flag) != 0 && !player.hasPermission(permission)) { - flags &= ~flag; - } - } - } - - @Command( - aliases = { "remove", "rem", "rement" }, - usage = " ", - desc = "Remove all entities of a type", - min = 2, - max = 2 - ) - @CommandPermissions("worldedit.remove") - @Logging(PLACEMENT) - @Console - public void remove(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - String typeStr = args.getString(0); - int radius = args.getInteger(1); - - if (radius < -1) { - player.printError("Use -1 to remove all entities in loaded chunks"); - return; - } - - EntityType type = null; - - if (typeStr.matches("all")) { - type = EntityType.ALL; - } else if (typeStr.matches("projectiles?|arrows?")) { - type = EntityType.PROJECTILES; - } else if (typeStr.matches("items?") - || typeStr.matches("drops?")) { - type = EntityType.ITEMS; - } else if (typeStr.matches("falling(blocks?|sand|gravel)")) { - type = EntityType.FALLING_BLOCKS; - } else if (typeStr.matches("paintings?") - || typeStr.matches("art")) { - type = EntityType.PAINTINGS; - } else if (typeStr.matches("(item)frames?")) { - type = EntityType.ITEM_FRAMES; - } else if (typeStr.matches("boats?")) { - type = EntityType.BOATS; - } else if (typeStr.matches("minecarts?") - || typeStr.matches("carts?")) { - type = EntityType.MINECARTS; - } else if (typeStr.matches("tnt")) { - type = EntityType.TNT; - } else if (typeStr.matches("xp")) { - type = EntityType.XP_ORBS; - } else { - player.printError("Acceptable types: projectiles, items, paintings, itemframes, boats, minecarts, tnt, xp, or all"); - return; - } - - int removed = 0; - if (player.isPlayer()) { - Vector origin = session.getPlacementPosition(player); - removed = player.getWorld().removeEntities(type, origin, radius); - } else { - for (LocalWorld world : we.getServer().getWorlds()) { - removed += world.removeEntities(type, new Vector(), radius); - } - } - player.print("Marked " + removed + " entit(ies) for removal."); - } - - @Command( - aliases = { "/help" }, - usage = "[]", - desc = "Displays help for the given command or lists all commands.", - min = 0, - max = -1 - ) - @Console - @CommandPermissions("worldedit.help") - public void help(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - help(args, we, session, player, editSession); - } - - public static void help(CommandContext args, WorldEdit we, LocalSession session, LocalPlayer player, EditSession editSession) { - final CommandsManager commandsManager = we.getCommandsManager(); - - if (args.argsLength() == 0) { - SortedSet commands = new TreeSet(new Comparator() { - @Override - public int compare(String o1, String o2) { - final int ret = o1.replaceAll("/", "").compareToIgnoreCase(o2.replaceAll("/", "")); - if (ret == 0) { - return o1.compareToIgnoreCase(o2); - } - return ret; - } - }); - commands.addAll(commandsManager.getCommands().keySet()); - - StringBuilder sb = new StringBuilder(); - boolean first = true; - for (String command : commands) { - if (!first) { - sb.append(", "); - } - - sb.append('/'); - sb.append(command); - first = false; - } - - player.print(sb.toString()); - - return; - } - - String command = args.getJoinedStrings(0).toLowerCase().replaceAll("/", ""); - - String helpMessage = commandsManager.getHelpMessages().get(command); - if (helpMessage == null) { - player.printError("Unknown command '" + command + "'."); - return; - } - - player.print(helpMessage); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command; + +import com.sk89q.minecraft.util.commands.*; +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.LocalWorld.KillFlags; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.patterns.Pattern; +import com.sk89q.worldedit.patterns.SingleBlockPattern; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; + +import java.util.Comparator; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import static com.sk89q.minecraft.util.commands.Logging.LogMode.PLACEMENT; + +/** + * Utility commands. + * + * @author sk89q + */ +public class UtilityCommands { + private final WorldEdit we; + + public UtilityCommands(WorldEdit we) { + this.we = we; + } + + @Command( + aliases = { "/fill" }, + usage = " [depth]", + desc = "Fill a hole", + min = 2, + max = 3 + ) + @CommandPermissions("worldedit.fill") + @Logging(PLACEMENT) + public void fill(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + Pattern pattern = we.getBlockPattern(player, args.getString(0)); + double radius = Math.max(1, args.getDouble(1)); + we.checkMaxRadius(radius); + int depth = args.argsLength() > 2 ? Math.max(1, args.getInteger(2)) : 1; + + Vector pos = session.getPlacementPosition(player); + int affected = 0; + if (pattern instanceof SingleBlockPattern) { + affected = editSession.fillXZ(pos, + ((SingleBlockPattern) pattern).getBlock(), + radius, depth, false); + } else { + affected = editSession.fillXZ(pos, pattern, radius, depth, false); + } + player.print(affected + " block(s) have been created."); + } + + @Command( + aliases = { "/fillr" }, + usage = " [depth]", + desc = "Fill a hole recursively", + min = 2, + max = 3 + ) + @CommandPermissions("worldedit.fill.recursive") + @Logging(PLACEMENT) + public void fillr(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + Pattern pattern = we.getBlockPattern(player, args.getString(0)); + double radius = Math.max(1, args.getDouble(1)); + we.checkMaxRadius(radius); + int depth = args.argsLength() > 2 ? Math.max(1, args.getInteger(2)) : Integer.MAX_VALUE; + + Vector pos = session.getPlacementPosition(player); + int affected = 0; + if (pattern instanceof SingleBlockPattern) { + affected = editSession.fillXZ(pos, + ((SingleBlockPattern) pattern).getBlock(), + radius, depth, true); + } else { + affected = editSession.fillXZ(pos, pattern, radius, depth, true); + } + player.print(affected + " block(s) have been created."); + } + + @Command( + aliases = { "/drain" }, + usage = "", + desc = "Drain a pool", + min = 1, + max = 1 + ) + @CommandPermissions("worldedit.drain") + @Logging(PLACEMENT) + public void drain(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + double radius = Math.max(0, args.getDouble(0)); + we.checkMaxRadius(radius); + int affected = editSession.drainArea( + session.getPlacementPosition(player), radius); + player.print(affected + " block(s) have been changed."); + } + + @Command( + aliases = { "/fixlava", "fixlava" }, + usage = "", + desc = "Fix lava to be stationary", + min = 1, + max = 1 + ) + @CommandPermissions("worldedit.fixlava") + @Logging(PLACEMENT) + public void fixLava(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + double radius = Math.max(0, args.getDouble(0)); + we.checkMaxRadius(radius); + int affected = editSession.fixLiquid( + session.getPlacementPosition(player), radius, 10, 11); + player.print(affected + " block(s) have been changed."); + } + + @Command( + aliases = { "/fixwater", "fixwater" }, + usage = "", + desc = "Fix water to be stationary", + min = 1, + max = 1 + ) + @CommandPermissions("worldedit.fixwater") + @Logging(PLACEMENT) + public void fixWater(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + double radius = Math.max(0, args.getDouble(0)); + we.checkMaxRadius(radius); + int affected = editSession.fixLiquid( + session.getPlacementPosition(player), radius, 8, 9); + player.print(affected + " block(s) have been changed."); + } + + @Command( + aliases = { "/removeabove", "removeabove" }, + usage = "[size] [height]", + desc = "Remove blocks above your head.", + min = 0, + max = 2 + ) + @CommandPermissions("worldedit.removeabove") + @Logging(PLACEMENT) + public void removeAbove(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 1; + we.checkMaxRadius(size); + LocalWorld world = player.getWorld(); + int height = args.argsLength() > 1 ? Math.min((world.getMaxY() + 1), args.getInteger(1) + 2) : (world.getMaxY() + 1); + + int affected = editSession.removeAbove( + session.getPlacementPosition(player), size, height); + player.print(affected + " block(s) have been removed."); + } + + @Command( + aliases = { "/removebelow", "removebelow" }, + usage = "[size] [height]", + desc = "Remove blocks below you.", + min = 0, + max = 2 + ) + @CommandPermissions("worldedit.removebelow") + @Logging(PLACEMENT) + public void removeBelow(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 1; + we.checkMaxRadius(size); + LocalWorld world = player.getWorld(); + int height = args.argsLength() > 1 ? Math.min((world.getMaxY() + 1), args.getInteger(1) + 2) : (world.getMaxY() + 1); + + int affected = editSession.removeBelow(session.getPlacementPosition(player), size, height); + player.print(affected + " block(s) have been removed."); + } + + @Command( + aliases = { "/removenear", "removenear" }, + usage = " [size]", + desc = "Remove blocks near you.", + min = 1, + max = 2 + ) + @CommandPermissions("worldedit.removenear") + @Logging(PLACEMENT) + public void removeNear(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + BaseBlock block = we.getBlock(player, args.getString(0), true); + int size = Math.max(1, args.getInteger(1, 50)); + we.checkMaxRadius(size); + + int affected = editSession.removeNear(session.getPlacementPosition(player), block.getType(), size); + player.print(affected + " block(s) have been removed."); + } + + @Command( + aliases = { "/replacenear", "replacenear" }, + usage = " ", + desc = "Replace nearby blocks", + flags = "f", + min = 3, + max = 3 + ) + @CommandPermissions("worldedit.replacenear") + @Logging(PLACEMENT) + public void replaceNear(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + int size = Math.max(1, args.getInteger(0)); + int affected; + Set from; + Pattern to; + if (args.argsLength() == 2) { + from = null; + to = we.getBlockPattern(player, args.getString(1)); + } else { + from = we.getBlocks(player, args.getString(1), true, !args.hasFlag('f')); + to = we.getBlockPattern(player, args.getString(2)); + } + + Vector base = session.getPlacementPosition(player); + Vector min = base.subtract(size, size, size); + Vector max = base.add(size, size, size); + Region region = new CuboidRegion(player.getWorld(), min, max); + + if (to instanceof SingleBlockPattern) { + affected = editSession.replaceBlocks(region, from, ((SingleBlockPattern) to).getBlock()); + } else { + affected = editSession.replaceBlocks(region, from, to); + } + player.print(affected + " block(s) have been replaced."); + } + + @Command( + aliases = { "/snow", "snow" }, + usage = "[radius]", + desc = "Simulates snow", + min = 0, + max = 1 + ) + @CommandPermissions("worldedit.snow") + @Logging(PLACEMENT) + public void snow(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + double size = args.argsLength() > 0 ? Math.max(1, args.getDouble(0)) : 10; + + int affected = editSession.simulateSnow(session.getPlacementPosition(player), size); + player.print(affected + " surfaces covered. Let it snow~"); + } + + @Command( + aliases = {"/thaw", "thaw"}, + usage = "[radius]", + desc = "Thaws the area", + min = 0, + max = 1 + ) + @CommandPermissions("worldedit.thaw") + @Logging(PLACEMENT) + public void thaw(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + double size = args.argsLength() > 0 ? Math.max(1, args.getDouble(0)) : 10; + + int affected = editSession.thaw(session.getPlacementPosition(player), size); + player.print(affected + " surfaces thawed."); + } + + @Command( + aliases = { "/green", "green" }, + usage = "[radius]", + desc = "Greens the area", + flags = "f", + min = 0, + max = 1 + ) + @CommandPermissions("worldedit.green") + @Logging(PLACEMENT) + public void green(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + final double size = args.argsLength() > 0 ? Math.max(1, args.getDouble(0)) : 10; + final boolean onlyNormalDirt = !args.hasFlag('f'); + + final int affected = editSession.green(session.getPlacementPosition(player), size, onlyNormalDirt); + player.print(affected + " surfaces greened."); + } + + @Command( + aliases = { "/ex", "/ext", "/extinguish", "ex", "ext", "extinguish" }, + usage = "[radius]", + desc = "Extinguish nearby fire", + min = 0, + max = 1 + ) + @CommandPermissions("worldedit.extinguish") + @Logging(PLACEMENT) + public void extinguish(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + LocalConfiguration config = we.getConfiguration(); + + int defaultRadius = config.maxRadius != -1 ? Math.min(40, config.maxRadius) : 40; + int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) + : defaultRadius; + we.checkMaxRadius(size); + + int affected = editSession.removeNear(session.getPlacementPosition(player), 51, size); + player.print(affected + " block(s) have been removed."); + } + + @Command( + aliases = { "butcher" }, + usage = "[radius]", + flags = "plangbf", + desc = "Kill all or nearby mobs", + help = + "Kills nearby mobs, based on radius, if none is given uses default in configuration.\n" + + "Flags:" + + " -p also kills pets.\n" + + " -n also kills NPCs.\n" + + " -g also kills Golems.\n" + + " -a also kills animals.\n" + + " -b also kills ambient mobs.\n" + + " -f compounds all previous flags.\n" + + " -l strikes lightning on each killed mob.", + min = 0, + max = 1 + ) + @CommandPermissions("worldedit.butcher") + @Logging(PLACEMENT) + @Console + public void butcher(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + LocalConfiguration config = we.getConfiguration(); + + // technically the default can be larger than the max, but that's not my problem + int radius = config.butcherDefaultRadius; + + // there might be a better way to do this but my brain is fried right now + if (args.argsLength() > 0) { // user inputted radius, override the default + radius = args.getInteger(0); + if (config.butcherMaxRadius != -1) { // clamp if there is a max + if (radius == -1) { + radius = config.butcherMaxRadius; + } else { // Math.min does not work if radius is -1 (actually highest possible value) + radius = Math.min(radius, config.butcherMaxRadius); + } + } + } + + FlagContainer flags = new FlagContainer(player); + flags.or(KillFlags.FRIENDLY , args.hasFlag('f')); // No permission check here. Flags will instead be filtered by the subsequent calls. + flags.or(KillFlags.PETS , args.hasFlag('p'), "worldedit.butcher.pets"); + flags.or(KillFlags.NPCS , args.hasFlag('n'), "worldedit.butcher.npcs"); + flags.or(KillFlags.GOLEMS , args.hasFlag('g'), "worldedit.butcher.golems"); + flags.or(KillFlags.ANIMALS , args.hasFlag('a'), "worldedit.butcher.animals"); + flags.or(KillFlags.AMBIENT , args.hasFlag('b'), "worldedit.butcher.ambient"); + flags.or(KillFlags.WITH_LIGHTNING, args.hasFlag('l'), "worldedit.butcher.lightning"); + // If you add flags here, please add them to com.sk89q.worldedit.commands.BrushCommands.butcherBrush() as well + + int killed; + if (player.isPlayer()) { + killed = player.getWorld().killMobs(session.getPlacementPosition(player), radius, flags.flags); + } else { + killed = 0; + for (LocalWorld world : we.getServer().getWorlds()) { + killed += world.killMobs(new Vector(), radius, flags.flags); + } + } + + if (radius < 0) { + player.print("Killed " + killed + " mobs."); + } else { + player.print("Killed " + killed + " mobs in a radius of " + radius + "."); + } + } + + public static class FlagContainer { + private final LocalPlayer player; + public int flags = 0; + public FlagContainer(LocalPlayer player) { + this.player = player; + } + + public void or(int flag, boolean on) { + if (on) flags |= flag; + } + + public void or(int flag, boolean on, String permission) { + or(flag, on); + + if ((flags & flag) != 0 && !player.hasPermission(permission)) { + flags &= ~flag; + } + } + } + + @Command( + aliases = { "remove", "rem", "rement" }, + usage = " ", + desc = "Remove all entities of a type", + min = 2, + max = 2 + ) + @CommandPermissions("worldedit.remove") + @Logging(PLACEMENT) + @Console + public void remove(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + String typeStr = args.getString(0); + int radius = args.getInteger(1); + + if (radius < -1) { + player.printError("Use -1 to remove all entities in loaded chunks"); + return; + } + + EntityType type = null; + + if (typeStr.matches("all")) { + type = EntityType.ALL; + } else if (typeStr.matches("projectiles?|arrows?")) { + type = EntityType.PROJECTILES; + } else if (typeStr.matches("items?") + || typeStr.matches("drops?")) { + type = EntityType.ITEMS; + } else if (typeStr.matches("falling(blocks?|sand|gravel)")) { + type = EntityType.FALLING_BLOCKS; + } else if (typeStr.matches("paintings?") + || typeStr.matches("art")) { + type = EntityType.PAINTINGS; + } else if (typeStr.matches("(item)frames?")) { + type = EntityType.ITEM_FRAMES; + } else if (typeStr.matches("boats?")) { + type = EntityType.BOATS; + } else if (typeStr.matches("minecarts?") + || typeStr.matches("carts?")) { + type = EntityType.MINECARTS; + } else if (typeStr.matches("tnt")) { + type = EntityType.TNT; + } else if (typeStr.matches("xp")) { + type = EntityType.XP_ORBS; + } else { + player.printError("Acceptable types: projectiles, items, paintings, itemframes, boats, minecarts, tnt, xp, or all"); + return; + } + + int removed = 0; + if (player.isPlayer()) { + Vector origin = session.getPlacementPosition(player); + removed = player.getWorld().removeEntities(type, origin, radius); + } else { + for (LocalWorld world : we.getServer().getWorlds()) { + removed += world.removeEntities(type, new Vector(), radius); + } + } + player.print("Marked " + removed + " entit(ies) for removal."); + } + + @Command( + aliases = { "/help" }, + usage = "[]", + desc = "Displays help for the given command or lists all commands.", + min = 0, + max = -1 + ) + @Console + @CommandPermissions("worldedit.help") + public void help(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + help(args, we, session, player, editSession); + } + + public static void help(CommandContext args, WorldEdit we, LocalSession session, LocalPlayer player, EditSession editSession) { + final CommandsManager commandsManager = we.getCommandsManager(); + + if (args.argsLength() == 0) { + SortedSet commands = new TreeSet(new Comparator() { + @Override + public int compare(String o1, String o2) { + final int ret = o1.replaceAll("/", "").compareToIgnoreCase(o2.replaceAll("/", "")); + if (ret == 0) { + return o1.compareToIgnoreCase(o2); + } + return ret; + } + }); + commands.addAll(commandsManager.getCommands().keySet()); + + StringBuilder sb = new StringBuilder(); + boolean first = true; + for (String command : commands) { + if (!first) { + sb.append(", "); + } + + sb.append('/'); + sb.append(command); + first = false; + } + + player.print(sb.toString()); + + return; + } + + String command = args.getJoinedStrings(0).toLowerCase().replaceAll("/", ""); + + String helpMessage = commandsManager.getHelpMessages().get(command); + if (helpMessage == null) { + player.printError("Unknown command '" + command + "'."); + return; + } + + player.print(helpMessage); + } +} diff --git a/src/main/java/com/sk89q/worldedit/commands/WorldEditCommands.java b/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/commands/WorldEditCommands.java rename to src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java index 31d9838f9..b97dd80ae 100644 --- a/src/main/java/com/sk89q/worldedit/commands/WorldEditCommands.java +++ b/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java @@ -1,120 +1,120 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.commands; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.TimeZone; -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.Console; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.WorldEditException; - -public class WorldEditCommands { - private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); - - private final WorldEdit we; - - public WorldEditCommands(WorldEdit we) { - this.we = we; - } - - @Command( - aliases = { "version", "ver" }, - usage = "", - desc = "Get WorldEdit version", - min = 0, - max = 0 - ) - @Console - public void version(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - player.print("WorldEdit version " + WorldEdit.getVersion()); - player.print("http://www.sk89q.com/projects/worldedit/"); - } - - @Command( - aliases = { "reload" }, - usage = "", - desc = "Reload WorldEdit", - min = 0, - max = 0 - ) - @CommandPermissions("worldedit.reload") - @Console - public void reload(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - we.getServer().reload(); - player.print("Configuration reloaded!"); - } - - @Command( - aliases = { "cui" }, - usage = "", - desc = "Complete CUI handshake", - min = 0, - max = 0 - ) - public void cui(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - session.setCUISupport(true); - session.dispatchCUISetup(player); - } - - @Command( - aliases = { "tz" }, - usage = "[timezone]", - desc = "Set your timezone", - min = 1, - max = 1 - ) - @Console - public void tz(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - TimeZone tz = TimeZone.getTimeZone(args.getString(0)); - session.setTimezone(tz); - player.print("Timezone set for this session to: " + tz.getDisplayName()); - player.print("The current time in that timezone is: " - + dateFormat.format(Calendar.getInstance(tz).getTime())); - } - - @Command( - aliases = { "help" }, - usage = "[]", - desc = "Displays help for the given command or lists all commands.", - min = 0, - max = -1 - ) - @CommandPermissions("worldedit.help") - @Console - public void help(CommandContext args, LocalSession session, LocalPlayer player, - EditSession editSession) throws WorldEditException { - - UtilityCommands.help(args, we, session, player, editSession); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.command; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.TimeZone; +import com.sk89q.minecraft.util.commands.Command; +import com.sk89q.minecraft.util.commands.CommandContext; +import com.sk89q.minecraft.util.commands.CommandPermissions; +import com.sk89q.minecraft.util.commands.Console; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; + +public class WorldEditCommands { + private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); + + private final WorldEdit we; + + public WorldEditCommands(WorldEdit we) { + this.we = we; + } + + @Command( + aliases = { "version", "ver" }, + usage = "", + desc = "Get WorldEdit version", + min = 0, + max = 0 + ) + @Console + public void version(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + player.print("WorldEdit version " + WorldEdit.getVersion()); + player.print("http://www.sk89q.com/projects/worldedit/"); + } + + @Command( + aliases = { "reload" }, + usage = "", + desc = "Reload WorldEdit", + min = 0, + max = 0 + ) + @CommandPermissions("worldedit.reload") + @Console + public void reload(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + we.getServer().reload(); + player.print("Configuration reloaded!"); + } + + @Command( + aliases = { "cui" }, + usage = "", + desc = "Complete CUI handshake", + min = 0, + max = 0 + ) + public void cui(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + session.setCUISupport(true); + session.dispatchCUISetup(player); + } + + @Command( + aliases = { "tz" }, + usage = "[timezone]", + desc = "Set your timezone", + min = 1, + max = 1 + ) + @Console + public void tz(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + TimeZone tz = TimeZone.getTimeZone(args.getString(0)); + session.setTimezone(tz); + player.print("Timezone set for this session to: " + tz.getDisplayName()); + player.print("The current time in that timezone is: " + + dateFormat.format(Calendar.getInstance(tz).getTime())); + } + + @Command( + aliases = { "help" }, + usage = "[]", + desc = "Displays help for the given command or lists all commands.", + min = 0, + max = -1 + ) + @CommandPermissions("worldedit.help") + @Console + public void help(CommandContext args, LocalSession session, LocalPlayer player, + EditSession editSession) throws WorldEditException { + + UtilityCommands.help(args, we, session, player, editSession); + } +} diff --git a/src/main/java/com/sk89q/worldedit/tools/AreaPickaxe.java b/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/tools/AreaPickaxe.java rename to src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java index 09980e24e..1ff96891b 100644 --- a/src/main/java/com/sk89q/worldedit/tools/AreaPickaxe.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java @@ -1,87 +1,87 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.tools; - -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.blocks.BlockID; - -/** - * A super pickaxe mode that will remove blocks in an area. - * - * @author sk89q - */ -public class AreaPickaxe implements BlockTool { - private static final BaseBlock air = new BaseBlock(0); - private int range; - - public AreaPickaxe(int range) { - this.range = range; - } - - public boolean canUse(LocalPlayer player) { - return player.hasPermission("worldedit.superpickaxe.area"); - } - - public boolean actPrimary(ServerInterface server, LocalConfiguration config, - LocalPlayer player, LocalSession session, WorldVector clicked) { - LocalWorld world = clicked.getWorld(); - int ox = clicked.getBlockX(); - int oy = clicked.getBlockY(); - int oz = clicked.getBlockZ(); - int initialType = world.getBlockType(clicked); - - if (initialType == 0) { - return true; - } - - if (initialType == BlockID.BEDROCK && !player.canDestroyBedrock()) { - return true; - } - - EditSession editSession = session.createEditSession(player); - - try { - for (int x = ox - range; x <= ox + range; ++x) { - for (int y = oy - range; y <= oy + range; ++y) { - for (int z = oz - range; z <= oz + range; ++z) { - Vector pos = new Vector(x, y, z); - if (world.getBlockType(pos) != initialType) { - continue; - } - if (config.superPickaxeManyDrop) { - world.simulateBlockMine(pos); - } - - world.queueBlockBreakEffect(server, pos, initialType, clicked.distanceSq(pos)); - - editSession.setBlock(pos, air); - } - } - } - } catch (MaxChangedBlocksException e) { - player.printError("Max blocks change limit reached."); - } finally { - session.remember(editSession); - } - - return true; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command.tool; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockID; + +/** + * A super pickaxe mode that will remove blocks in an area. + * + * @author sk89q + */ +public class AreaPickaxe implements BlockTool { + private static final BaseBlock air = new BaseBlock(0); + private int range; + + public AreaPickaxe(int range) { + this.range = range; + } + + public boolean canUse(LocalPlayer player) { + return player.hasPermission("worldedit.superpickaxe.area"); + } + + public boolean actPrimary(ServerInterface server, LocalConfiguration config, + LocalPlayer player, LocalSession session, WorldVector clicked) { + LocalWorld world = clicked.getWorld(); + int ox = clicked.getBlockX(); + int oy = clicked.getBlockY(); + int oz = clicked.getBlockZ(); + int initialType = world.getBlockType(clicked); + + if (initialType == 0) { + return true; + } + + if (initialType == BlockID.BEDROCK && !player.canDestroyBedrock()) { + return true; + } + + EditSession editSession = session.createEditSession(player); + + try { + for (int x = ox - range; x <= ox + range; ++x) { + for (int y = oy - range; y <= oy + range; ++y) { + for (int z = oz - range; z <= oz + range; ++z) { + Vector pos = new Vector(x, y, z); + if (world.getBlockType(pos) != initialType) { + continue; + } + if (config.superPickaxeManyDrop) { + world.simulateBlockMine(pos); + } + + world.queueBlockBreakEffect(server, pos, initialType, clicked.distanceSq(pos)); + + editSession.setBlock(pos, air); + } + } + } + } catch (MaxChangedBlocksException e) { + player.printError("Max blocks change limit reached."); + } finally { + session.remember(editSession); + } + + return true; + } +} diff --git a/src/main/java/com/sk89q/worldedit/tools/BlockDataCyler.java b/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/tools/BlockDataCyler.java rename to src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java index 3ea507555..eeac59eaf 100644 --- a/src/main/java/com/sk89q/worldedit/tools/BlockDataCyler.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java @@ -1,74 +1,74 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.tools; - -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.blocks.BaseBlock; - -/** - * A mode that cycles the data values of supported blocks. - * - * @author sk89q - */ -public class BlockDataCyler implements DoubleActionBlockTool { - - public boolean canUse(LocalPlayer player) { - return player.hasPermission("worldedit.tool.data-cycler"); - } - - private boolean handleCycle(ServerInterface server, LocalConfiguration config, - LocalPlayer player, LocalSession session, WorldVector clicked, boolean forward) { - - LocalWorld world = clicked.getWorld(); - - int type = world.getBlockType(clicked); - int data = world.getBlockData(clicked); - - if (config.allowedDataCycleBlocks.size() > 0 - && !player.hasPermission("worldedit.override.data-cycler") - && !config.allowedDataCycleBlocks.contains(type)) { - player.printError("You are not permitted to cycle the data value of that block."); - return true; - } - - int increment = forward ? 1 : -1; - data = (new BaseBlock(type, data)).cycleData(increment); - - if (data < 0) { - player.printError("That block's data cannot be cycled!"); - } else { - world.setBlockData(clicked, data); - } - - return true; - } - - public boolean actPrimary(ServerInterface server, LocalConfiguration config, - LocalPlayer player, LocalSession session, WorldVector clicked) { - return handleCycle(server, config, player, session, clicked, true); - } - - public boolean actSecondary(ServerInterface server, - LocalConfiguration config, LocalPlayer player, - LocalSession session, WorldVector clicked) { - return handleCycle(server, config, player, session, clicked, false); - } - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command.tool; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.blocks.BaseBlock; + +/** + * A mode that cycles the data values of supported blocks. + * + * @author sk89q + */ +public class BlockDataCyler implements DoubleActionBlockTool { + + public boolean canUse(LocalPlayer player) { + return player.hasPermission("worldedit.tool.data-cycler"); + } + + private boolean handleCycle(ServerInterface server, LocalConfiguration config, + LocalPlayer player, LocalSession session, WorldVector clicked, boolean forward) { + + LocalWorld world = clicked.getWorld(); + + int type = world.getBlockType(clicked); + int data = world.getBlockData(clicked); + + if (config.allowedDataCycleBlocks.size() > 0 + && !player.hasPermission("worldedit.override.data-cycler") + && !config.allowedDataCycleBlocks.contains(type)) { + player.printError("You are not permitted to cycle the data value of that block."); + return true; + } + + int increment = forward ? 1 : -1; + data = (new BaseBlock(type, data)).cycleData(increment); + + if (data < 0) { + player.printError("That block's data cannot be cycled!"); + } else { + world.setBlockData(clicked, data); + } + + return true; + } + + public boolean actPrimary(ServerInterface server, LocalConfiguration config, + LocalPlayer player, LocalSession session, WorldVector clicked) { + return handleCycle(server, config, player, session, clicked, true); + } + + public boolean actSecondary(ServerInterface server, + LocalConfiguration config, LocalPlayer player, + LocalSession session, WorldVector clicked) { + return handleCycle(server, config, player, session, clicked, false); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/tools/BlockReplacer.java b/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/tools/BlockReplacer.java rename to src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java index d6b829171..18a3e5a3d 100644 --- a/src/main/java/com/sk89q/worldedit/tools/BlockReplacer.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java @@ -1,80 +1,80 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.tools; - -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.bags.BlockBag; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.blocks.BlockType; - -/** - * A mode that replaces one block. - * - * @author sk89q - */ -public class BlockReplacer implements DoubleActionBlockTool { - private BaseBlock targetBlock; - - public BlockReplacer(BaseBlock targetBlock) { - this.targetBlock = targetBlock; - } - - public boolean canUse(LocalPlayer player) { - return player.hasPermission("worldedit.tool.replacer"); - } - - public boolean actPrimary(ServerInterface server, LocalConfiguration config, - LocalPlayer player, LocalSession session, WorldVector clicked) { - - BlockBag bag = session.getBlockBag(player); - - LocalWorld world = clicked.getWorld(); - EditSession editSession = WorldEdit.getInstance().getEditSessionFactory().getEditSession(world, -1, bag, player); - - try { - editSession.setBlock(clicked, targetBlock); - } catch (MaxChangedBlocksException e) { - } finally { - if (bag != null) { - bag.flushChanges(); - } - session.remember(editSession); - } - - return true; - } - - public boolean actSecondary(ServerInterface server, - LocalConfiguration config, LocalPlayer player, - LocalSession session, WorldVector clicked) { - - LocalWorld world = clicked.getWorld(); - EditSession editSession = WorldEdit.getInstance().getEditSessionFactory().getEditSession(world, -1, player); - targetBlock = (editSession).getBlock(clicked); - BlockType type = BlockType.fromID(targetBlock.getType()); - - if (type != null) { - player.print("Replacer tool switched to: " + type.getName()); - } - - return true; - } - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command.tool; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockType; + +/** + * A mode that replaces one block. + * + * @author sk89q + */ +public class BlockReplacer implements DoubleActionBlockTool { + private BaseBlock targetBlock; + + public BlockReplacer(BaseBlock targetBlock) { + this.targetBlock = targetBlock; + } + + public boolean canUse(LocalPlayer player) { + return player.hasPermission("worldedit.tool.replacer"); + } + + public boolean actPrimary(ServerInterface server, LocalConfiguration config, + LocalPlayer player, LocalSession session, WorldVector clicked) { + + BlockBag bag = session.getBlockBag(player); + + LocalWorld world = clicked.getWorld(); + EditSession editSession = WorldEdit.getInstance().getEditSessionFactory().getEditSession(world, -1, bag, player); + + try { + editSession.setBlock(clicked, targetBlock); + } catch (MaxChangedBlocksException e) { + } finally { + if (bag != null) { + bag.flushChanges(); + } + session.remember(editSession); + } + + return true; + } + + public boolean actSecondary(ServerInterface server, + LocalConfiguration config, LocalPlayer player, + LocalSession session, WorldVector clicked) { + + LocalWorld world = clicked.getWorld(); + EditSession editSession = WorldEdit.getInstance().getEditSessionFactory().getEditSession(world, -1, player); + targetBlock = (editSession).getBlock(clicked); + BlockType type = BlockType.fromID(targetBlock.getType()); + + if (type != null) { + player.print("Replacer tool switched to: " + type.getName()); + } + + return true; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/tools/BlockTool.java b/src/main/java/com/sk89q/worldedit/command/tool/BlockTool.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/tools/BlockTool.java rename to src/main/java/com/sk89q/worldedit/command/tool/BlockTool.java index 4ecb1a503..8c40858fb 100644 --- a/src/main/java/com/sk89q/worldedit/tools/BlockTool.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/BlockTool.java @@ -1,43 +1,43 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.tools; - -import com.sk89q.worldedit.*; - -/** - * Represents a tool that uses a block.. - * - * @author sk89q - */ -public interface BlockTool extends Tool { - /** - * Perform the action. Should return true to deny the default - * action. - * - * @param server - * @param config - * @param player - * @param session - * @param clicked - * @return true to deny - */ - public boolean actPrimary(ServerInterface server, LocalConfiguration config, - LocalPlayer player, LocalSession session, WorldVector clicked); -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command.tool; + +import com.sk89q.worldedit.*; + +/** + * Represents a tool that uses a block.. + * + * @author sk89q + */ +public interface BlockTool extends Tool { + /** + * Perform the action. Should return true to deny the default + * action. + * + * @param server + * @param config + * @param player + * @param session + * @param clicked + * @return true to deny + */ + public boolean actPrimary(ServerInterface server, LocalConfiguration config, + LocalPlayer player, LocalSession session, WorldVector clicked); +} diff --git a/src/main/java/com/sk89q/worldedit/tools/BrushTool.java b/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java similarity index 92% rename from src/main/java/com/sk89q/worldedit/tools/BrushTool.java rename to src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java index 100036e2f..595198cae 100644 --- a/src/main/java/com/sk89q/worldedit/tools/BrushTool.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java @@ -1,208 +1,210 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.tools; - -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.bags.BlockBag; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.blocks.BlockID; -import com.sk89q.worldedit.masks.CombinedMask; -import com.sk89q.worldedit.masks.Mask; -import com.sk89q.worldedit.patterns.Pattern; -import com.sk89q.worldedit.patterns.SingleBlockPattern; -import com.sk89q.worldedit.tools.brushes.Brush; -import com.sk89q.worldedit.tools.brushes.SphereBrush; - -/** - * Builds a shape at the place being looked at. - * - * @author sk89q - */ -public class BrushTool implements TraceTool { - protected static int MAX_RANGE = 500; - protected int range = -1; - private Mask mask = null; - private Brush brush = new SphereBrush(); - private Pattern material = new SingleBlockPattern(new BaseBlock(BlockID.COBBLESTONE)); - private double size = 1; - private String permission; - - /** - * Construct the tool. - * - * @param permission - */ - public BrushTool(String permission) { - this.permission = permission; - } - - /** - * Checks to see if the player can still be using this tool (considering - * permissions and such). - * - * @param player - * @return - */ - public boolean canUse(LocalPlayer player) { - return player.hasPermission(permission); - } - - /** - * Get the filter. - * - * @return the filter - */ - public Mask getMask() { - return mask; - } - - /** - * Set the block filter used for identifying blocks to replace. - * - * @param filter the filter to set - */ - public void setMask(Mask filter) { - this.mask = filter; - } - - /** - * Set the brush. - * - * @param brush - * @param perm - */ - public void setBrush(Brush brush, String perm) { - this.brush = brush; - this.permission = perm; - } - - /** - * Get the current brush. - * - * @return - */ - public Brush getBrush() { - return brush; - } - - /** - * Set the material. - * - * @param material - */ - public void setFill(Pattern material) { - this.material = material; - } - - /** - * Get the material. - * - * @return - */ - public Pattern getMaterial() { - return material; - } - - /** - * Get the set brush size. - * - * @return - */ - public double getSize() { - return size; - } - - /** - * Set the set brush size. - * - * @param radius - */ - public void setSize(double radius) { - this.size = radius; - } - - /** - * Get the set brush range. - * - * @return - */ - public int getRange() { - return (range < 0) ? MAX_RANGE : Math.min(range, MAX_RANGE); - } - - /** - * Set the set brush range. - * - * @param size - */ - public void setRange(int range) { - this.range = range; - } - - /** - * Perform the action. Should return true to deny the default - * action. - * - * @param player - * @param session - * @return true to deny - */ - public boolean actPrimary(ServerInterface server, LocalConfiguration config, - LocalPlayer player, LocalSession session) { - WorldVector target = null; - target = player.getBlockTrace(getRange(), true); - - if (target == null) { - player.printError("No block in sight!"); - return true; - } - - BlockBag bag = session.getBlockBag(player); - - EditSession editSession = session.createEditSession(player); - if (mask != null) { - mask.prepare(session, player, target); - Mask existingMask = editSession.getMask(); - if (existingMask == null) { - editSession.setMask(mask); - } else if (existingMask instanceof CombinedMask) { - ((CombinedMask) existingMask).add(mask); - } else { - CombinedMask newMask = new CombinedMask(existingMask); - newMask.add(mask); - editSession.setMask(newMask); - } - } - - try { - brush.build(editSession, target, material, size); - } catch (MaxChangedBlocksException e) { - player.printError("Max blocks change limit reached."); - } finally { - if (bag != null) { - bag.flushChanges(); - } - session.remember(editSession); - } - - return true; - } - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command.tool; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockID; +import com.sk89q.worldedit.masks.CombinedMask; +import com.sk89q.worldedit.masks.Mask; +import com.sk89q.worldedit.patterns.Pattern; +import com.sk89q.worldedit.patterns.SingleBlockPattern; +import com.sk89q.worldedit.command.tool.brush.Brush; +import com.sk89q.worldedit.command.tool.brush.SphereBrush; +import com.sk89q.worldedit.session.request.Request; + +/** + * Builds a shape at the place being looked at. + * + * @author sk89q + */ +public class BrushTool implements TraceTool { + protected static int MAX_RANGE = 500; + protected int range = -1; + private Mask mask = null; + private Brush brush = new SphereBrush(); + private Pattern material = new SingleBlockPattern(new BaseBlock(BlockID.COBBLESTONE)); + private double size = 1; + private String permission; + + /** + * Construct the tool. + * + * @param permission + */ + public BrushTool(String permission) { + this.permission = permission; + } + + /** + * Checks to see if the player can still be using this tool (considering + * permissions and such). + * + * @param player + * @return + */ + public boolean canUse(LocalPlayer player) { + return player.hasPermission(permission); + } + + /** + * Get the filter. + * + * @return the filter + */ + public Mask getMask() { + return mask; + } + + /** + * Set the block filter used for identifying blocks to replace. + * + * @param filter the filter to set + */ + public void setMask(Mask filter) { + this.mask = filter; + } + + /** + * Set the brush. + * + * @param brush + * @param perm + */ + public void setBrush(Brush brush, String perm) { + this.brush = brush; + this.permission = perm; + } + + /** + * Get the current brush. + * + * @return + */ + public Brush getBrush() { + return brush; + } + + /** + * Set the material. + * + * @param material + */ + public void setFill(Pattern material) { + this.material = material; + } + + /** + * Get the material. + * + * @return + */ + public Pattern getMaterial() { + return material; + } + + /** + * Get the set brush size. + * + * @return + */ + public double getSize() { + return size; + } + + /** + * Set the set brush size. + * + * @param radius + */ + public void setSize(double radius) { + this.size = radius; + } + + /** + * Get the set brush range. + * + * @return + */ + public int getRange() { + return (range < 0) ? MAX_RANGE : Math.min(range, MAX_RANGE); + } + + /** + * Set the set brush range. + * + * @param size + */ + public void setRange(int range) { + this.range = range; + } + + /** + * Perform the action. Should return true to deny the default + * action. + * + * @param player + * @param session + * @return true to deny + */ + public boolean actPrimary(ServerInterface server, LocalConfiguration config, + LocalPlayer player, LocalSession session) { + WorldVector target = null; + target = player.getBlockTrace(getRange(), true); + + if (target == null) { + player.printError("No block in sight!"); + return true; + } + + BlockBag bag = session.getBlockBag(player); + + EditSession editSession = session.createEditSession(player); + Request.request().setEditSession(editSession); + if (mask != null) { + mask.prepare(session, player, target); + Mask existingMask = editSession.getMask(); + if (existingMask == null) { + editSession.setMask(mask); + } else if (existingMask instanceof CombinedMask) { + ((CombinedMask) existingMask).add(mask); + } else { + CombinedMask newMask = new CombinedMask(existingMask); + newMask.add(mask); + editSession.setMask(newMask); + } + } + + try { + brush.build(editSession, target, material, size); + } catch (MaxChangedBlocksException e) { + player.printError("Max blocks change limit reached."); + } finally { + if (bag != null) { + bag.flushChanges(); + } + session.remember(editSession); + } + + return true; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/tools/DistanceWand.java b/src/main/java/com/sk89q/worldedit/command/tool/DistanceWand.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/tools/DistanceWand.java rename to src/main/java/com/sk89q/worldedit/command/tool/DistanceWand.java index 74337aa94..797da0155 100644 --- a/src/main/java/com/sk89q/worldedit/tools/DistanceWand.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/DistanceWand.java @@ -1,90 +1,90 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.tools; - -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.regions.RegionSelector; - -/** - * A wand that can be used at a distance. - * - * @author wizjany - */ -public class DistanceWand extends BrushTool implements DoubleActionTraceTool { - - public DistanceWand() { - super("worldedit.wand"); - } - - @Override - public boolean canUse(LocalPlayer player) { - return player.hasPermission("worldedit.wand"); - } - - public boolean actSecondary(ServerInterface server, LocalConfiguration config, - LocalPlayer player, LocalSession session) { - if (session.isToolControlEnabled() && player.hasPermission("worldedit.selection.pos")) { - WorldVector target = getTarget(player); - if (target == null) return true; - - RegionSelector selector = session.getRegionSelector(player.getWorld()); - if (selector.selectPrimary(target)) { - selector.explainPrimarySelection(player, session, target); - } - return true; - - } - return false; - - } - - @Override - public boolean actPrimary(ServerInterface server, LocalConfiguration config, - LocalPlayer player, LocalSession session) { - if (session.isToolControlEnabled() && player.hasPermission("worldedit.selection.pos")) { - WorldVector target = getTarget(player); - if (target == null) return true; - - RegionSelector selector = session.getRegionSelector(player.getWorld()); - if (selector.selectSecondary(target)) { - selector.explainSecondarySelection(player, session, target); - } - return true; - - } - return false; - } - - public WorldVector getTarget(LocalPlayer player) { - WorldVector target = null; - if (this.range > -1) { - target = player.getBlockTrace(getRange(), true); - } else { - target = player.getBlockTrace(MAX_RANGE); - } - - if (target == null) { - player.printError("No block in sight!"); - return null; - } - - return target; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command.tool; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.regions.selector.RegionSelector; + +/** + * A wand that can be used at a distance. + * + * @author wizjany + */ +public class DistanceWand extends BrushTool implements DoubleActionTraceTool { + + public DistanceWand() { + super("worldedit.wand"); + } + + @Override + public boolean canUse(LocalPlayer player) { + return player.hasPermission("worldedit.wand"); + } + + public boolean actSecondary(ServerInterface server, LocalConfiguration config, + LocalPlayer player, LocalSession session) { + if (session.isToolControlEnabled() && player.hasPermission("worldedit.selection.pos")) { + WorldVector target = getTarget(player); + if (target == null) return true; + + RegionSelector selector = session.getRegionSelector(player.getWorld()); + if (selector.selectPrimary(target)) { + selector.explainPrimarySelection(player, session, target); + } + return true; + + } + return false; + + } + + @Override + public boolean actPrimary(ServerInterface server, LocalConfiguration config, + LocalPlayer player, LocalSession session) { + if (session.isToolControlEnabled() && player.hasPermission("worldedit.selection.pos")) { + WorldVector target = getTarget(player); + if (target == null) return true; + + RegionSelector selector = session.getRegionSelector(player.getWorld()); + if (selector.selectSecondary(target)) { + selector.explainSecondarySelection(player, session, target); + } + return true; + + } + return false; + } + + public WorldVector getTarget(LocalPlayer player) { + WorldVector target = null; + if (this.range > -1) { + target = player.getBlockTrace(getRange(), true); + } else { + target = player.getBlockTrace(MAX_RANGE); + } + + if (target == null) { + player.printError("No block in sight!"); + return null; + } + + return target; + } +} diff --git a/src/main/java/com/sk89q/worldedit/tools/DoubleActionBlockTool.java b/src/main/java/com/sk89q/worldedit/command/tool/DoubleActionBlockTool.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/tools/DoubleActionBlockTool.java rename to src/main/java/com/sk89q/worldedit/command/tool/DoubleActionBlockTool.java index 5145f738a..a48c3391f 100644 --- a/src/main/java/com/sk89q/worldedit/tools/DoubleActionBlockTool.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/DoubleActionBlockTool.java @@ -1,47 +1,47 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.tools; - -import com.sk89q.worldedit.LocalConfiguration; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.ServerInterface; -import com.sk89q.worldedit.WorldVector; - -/** - * Represents a block tool that also has a secondary/primary function. - * - * @author sk89q - */ -public interface DoubleActionBlockTool extends BlockTool { - /** - * Perform the secondary action. Should return true to deny the default - * action. - * - * @param server - * @param config - * @param player - * @param session - * @param clicked - * @return true to deny - */ - public boolean actSecondary(ServerInterface server, LocalConfiguration config, - LocalPlayer player, LocalSession session, WorldVector clicked); -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.command.tool; + +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.ServerInterface; +import com.sk89q.worldedit.WorldVector; + +/** + * Represents a block tool that also has a secondary/primary function. + * + * @author sk89q + */ +public interface DoubleActionBlockTool extends BlockTool { + /** + * Perform the secondary action. Should return true to deny the default + * action. + * + * @param server + * @param config + * @param player + * @param session + * @param clicked + * @return true to deny + */ + public boolean actSecondary(ServerInterface server, LocalConfiguration config, + LocalPlayer player, LocalSession session, WorldVector clicked); +} diff --git a/src/main/java/com/sk89q/worldedit/tools/DoubleActionTraceTool.java b/src/main/java/com/sk89q/worldedit/command/tool/DoubleActionTraceTool.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/tools/DoubleActionTraceTool.java rename to src/main/java/com/sk89q/worldedit/command/tool/DoubleActionTraceTool.java index 6dce525f4..43695bfe6 100644 --- a/src/main/java/com/sk89q/worldedit/tools/DoubleActionTraceTool.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/DoubleActionTraceTool.java @@ -1,43 +1,43 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.tools; - -import com.sk89q.worldedit.LocalConfiguration; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.ServerInterface; - -/** - * Represents a trace tool that also has a secondary/primary function. - */ -public interface DoubleActionTraceTool extends TraceTool { - /** - * Perform the secondary action. Should return true to deny the default - * action. - * - * @param server - * @param config - * @param player - * @param session - * @return true to deny - */ - public boolean actSecondary(ServerInterface server, LocalConfiguration config, - LocalPlayer player, LocalSession session); -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.command.tool; + +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.ServerInterface; + +/** + * Represents a trace tool that also has a secondary/primary function. + */ +public interface DoubleActionTraceTool extends TraceTool { + /** + * Perform the secondary action. Should return true to deny the default + * action. + * + * @param server + * @param config + * @param player + * @param session + * @return true to deny + */ + public boolean actSecondary(ServerInterface server, LocalConfiguration config, + LocalPlayer player, LocalSession session); +} diff --git a/src/main/java/com/sk89q/worldedit/tools/FloatingTreeRemover.java b/src/main/java/com/sk89q/worldedit/command/tool/FloatingTreeRemover.java old mode 100755 new mode 100644 similarity index 96% rename from src/main/java/com/sk89q/worldedit/tools/FloatingTreeRemover.java rename to src/main/java/com/sk89q/worldedit/command/tool/FloatingTreeRemover.java index dac067df2..4620aa00d --- a/src/main/java/com/sk89q/worldedit/tools/FloatingTreeRemover.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/FloatingTreeRemover.java @@ -1,166 +1,166 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.tools; - -import java.util.HashSet; -import java.util.LinkedList; -import java.util.Set; -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.blocks.BlockID; - -/** - * A pickaxe mode that removes floating treetops (logs and leaves not connected - * to anything else) - * - * @author Moo0 - */ -public class FloatingTreeRemover implements BlockTool { - private static final BaseBlock AIR = new BaseBlock(BlockID.AIR); - private int rangeSq; - - public FloatingTreeRemover() { - rangeSq = 100*100; - } - - public boolean canUse(LocalPlayer player) { - return player.hasPermission("worldedit.tool.deltree"); - } - - public boolean actPrimary(ServerInterface server, LocalConfiguration config, - LocalPlayer player, LocalSession session, WorldVector clicked) { - - final LocalWorld world = clicked.getWorld(); - - switch (world.getBlockType(clicked)) { - case BlockID.LOG: - case BlockID.LOG2: - case BlockID.LEAVES: - case BlockID.LEAVES2: - case BlockID.BROWN_MUSHROOM_CAP: - case BlockID.RED_MUSHROOM_CAP: - case BlockID.VINE: - break; - - default: - player.printError("That's not a tree."); - return true; - } - - final EditSession editSession = session.createEditSession(player); - - try { - final Set blockSet = bfs(world, clicked); - if (blockSet == null) { - player.printError("That's not a floating tree."); - return true; - } - - for (Vector blockVector : blockSet) { - final int typeId = editSession.getBlock(blockVector).getType(); - switch (typeId) { - case BlockID.LOG: - case BlockID.LOG2: - case BlockID.LEAVES: - case BlockID.LEAVES2: - case BlockID.BROWN_MUSHROOM_CAP: - case BlockID.RED_MUSHROOM_CAP: - case BlockID.VINE: - editSession.setBlock(blockVector, AIR); - } - } - } catch (MaxChangedBlocksException e) { - player.printError("Max blocks change limit reached."); - } finally { - session.remember(editSession); - } - - return true; - } - - Vector[] recurseDirections = { - PlayerDirection.NORTH.vector(), - PlayerDirection.EAST.vector(), - PlayerDirection.SOUTH.vector(), - PlayerDirection.WEST.vector(), - PlayerDirection.UP.vector(), - PlayerDirection.DOWN.vector(), - }; - - /** - * Helper method. - * - * @param world the world that contains the tree - * @param origin any point contained in the floating tree - * @return a set containing all blocks in the tree/shroom or null if this is not a floating tree/shroom. - */ - private Set bfs(LocalWorld world, Vector origin) throws MaxChangedBlocksException { - final Set visited = new HashSet(); - final LinkedList queue = new LinkedList(); - - queue.addLast(origin); - visited.add(origin); - - while (!queue.isEmpty()) { - final Vector current = queue.removeFirst(); - for (Vector recurseDirection : recurseDirections) { - final Vector next = current.add(recurseDirection); - if (origin.distanceSq(next) > rangeSq) { - // Maximum range exceeded => stop walking - continue; - } - - if (visited.add(next)) { - switch (world.getBlockType(next)) { - case BlockID.AIR: - case BlockID.SNOW: - // we hit air or snow => stop walking this route - continue; - - case BlockID.LOG: - case BlockID.LOG2: - case BlockID.LEAVES: - case BlockID.LEAVES2: - case BlockID.BROWN_MUSHROOM_CAP: - case BlockID.RED_MUSHROOM_CAP: - case BlockID.VINE: - // queue next point - queue.addLast(next); - break; - - default: - // we hit something solid - evaluate where we came from - final int curId = world.getBlockType(current); - if (curId == BlockID.LEAVES || curId == BlockID.LEAVES2 - || curId == BlockID.VINE) { - // leaves touching a wall/the ground => stop walking this route - continue; - } else { - // log/shroom touching a wall/the ground => this is not a floating tree, bail out - return null; - } - } // switch - } // if - } // for - } // while - - return visited; - } // bfs -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command.tool; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Set; +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockID; + +/** + * A pickaxe mode that removes floating treetops (logs and leaves not connected + * to anything else) + * + * @author Moo0 + */ +public class FloatingTreeRemover implements BlockTool { + private static final BaseBlock AIR = new BaseBlock(BlockID.AIR); + private int rangeSq; + + public FloatingTreeRemover() { + rangeSq = 100*100; + } + + public boolean canUse(LocalPlayer player) { + return player.hasPermission("worldedit.tool.deltree"); + } + + public boolean actPrimary(ServerInterface server, LocalConfiguration config, + LocalPlayer player, LocalSession session, WorldVector clicked) { + + final LocalWorld world = clicked.getWorld(); + + switch (world.getBlockType(clicked)) { + case BlockID.LOG: + case BlockID.LOG2: + case BlockID.LEAVES: + case BlockID.LEAVES2: + case BlockID.BROWN_MUSHROOM_CAP: + case BlockID.RED_MUSHROOM_CAP: + case BlockID.VINE: + break; + + default: + player.printError("That's not a tree."); + return true; + } + + final EditSession editSession = session.createEditSession(player); + + try { + final Set blockSet = bfs(world, clicked); + if (blockSet == null) { + player.printError("That's not a floating tree."); + return true; + } + + for (Vector blockVector : blockSet) { + final int typeId = editSession.getBlock(blockVector).getType(); + switch (typeId) { + case BlockID.LOG: + case BlockID.LOG2: + case BlockID.LEAVES: + case BlockID.LEAVES2: + case BlockID.BROWN_MUSHROOM_CAP: + case BlockID.RED_MUSHROOM_CAP: + case BlockID.VINE: + editSession.setBlock(blockVector, AIR); + } + } + } catch (MaxChangedBlocksException e) { + player.printError("Max blocks change limit reached."); + } finally { + session.remember(editSession); + } + + return true; + } + + Vector[] recurseDirections = { + PlayerDirection.NORTH.vector(), + PlayerDirection.EAST.vector(), + PlayerDirection.SOUTH.vector(), + PlayerDirection.WEST.vector(), + PlayerDirection.UP.vector(), + PlayerDirection.DOWN.vector(), + }; + + /** + * Helper method. + * + * @param world the world that contains the tree + * @param origin any point contained in the floating tree + * @return a set containing all blocks in the tree/shroom or null if this is not a floating tree/shroom. + */ + private Set bfs(LocalWorld world, Vector origin) throws MaxChangedBlocksException { + final Set visited = new HashSet(); + final LinkedList queue = new LinkedList(); + + queue.addLast(origin); + visited.add(origin); + + while (!queue.isEmpty()) { + final Vector current = queue.removeFirst(); + for (Vector recurseDirection : recurseDirections) { + final Vector next = current.add(recurseDirection); + if (origin.distanceSq(next) > rangeSq) { + // Maximum range exceeded => stop walking + continue; + } + + if (visited.add(next)) { + switch (world.getBlockType(next)) { + case BlockID.AIR: + case BlockID.SNOW: + // we hit air or snow => stop walking this route + continue; + + case BlockID.LOG: + case BlockID.LOG2: + case BlockID.LEAVES: + case BlockID.LEAVES2: + case BlockID.BROWN_MUSHROOM_CAP: + case BlockID.RED_MUSHROOM_CAP: + case BlockID.VINE: + // queue next point + queue.addLast(next); + break; + + default: + // we hit something solid - evaluate where we came from + final int curId = world.getBlockType(current); + if (curId == BlockID.LEAVES || curId == BlockID.LEAVES2 + || curId == BlockID.VINE) { + // leaves touching a wall/the ground => stop walking this route + continue; + } else { + // log/shroom touching a wall/the ground => this is not a floating tree, bail out + return null; + } + } // switch + } // if + } // for + } // while + + return visited; + } // bfs +} diff --git a/src/main/java/com/sk89q/worldedit/tools/FloodFillTool.java b/src/main/java/com/sk89q/worldedit/command/tool/FloodFillTool.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/tools/FloodFillTool.java rename to src/main/java/com/sk89q/worldedit/command/tool/FloodFillTool.java index ba81116d3..f4901eac4 100644 --- a/src/main/java/com/sk89q/worldedit/tools/FloodFillTool.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/FloodFillTool.java @@ -1,118 +1,118 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.tools; - -import java.util.HashSet; -import java.util.Set; -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.blocks.BlockID; -import com.sk89q.worldedit.patterns.Pattern; - -/** - * A tool that flood fills blocks. - * - * @author sk89q - */ -public class FloodFillTool implements BlockTool { - private int range; - private Pattern pattern; - - public FloodFillTool(int range, Pattern pattern) { - this.range = range; - this.pattern = pattern; - } - - public boolean canUse(LocalPlayer player) { - return player.hasPermission("worldedit.tool.flood-fill"); - } - - public boolean actPrimary(ServerInterface server, LocalConfiguration config, - LocalPlayer player, LocalSession session, WorldVector clicked) { - LocalWorld world = clicked.getWorld(); - - int initialType = world.getBlockType(clicked); - - if (initialType == BlockID.AIR) { - return true; - } - - if (initialType == BlockID.BEDROCK && !player.canDestroyBedrock()) { - return true; - } - - EditSession editSession = session.createEditSession(player); - - try { - recurse(server, editSession, world, clicked.toBlockVector(), - clicked, range, initialType, new HashSet()); - } catch (MaxChangedBlocksException e) { - player.printError("Max blocks change limit reached."); - } finally { - session.remember(editSession); - } - - return true; - } - - /** - * Helper method. - * - * @param server - * @param superPickaxeManyDrop - * @param world - * @param pos - * @param origin - * @param size - * @param initialType - * @param visited - */ - private void recurse(ServerInterface server, EditSession editSession, - LocalWorld world, BlockVector pos, - Vector origin, int size, int initialType, - Set visited) - throws MaxChangedBlocksException { - - if (origin.distance(pos) > size || visited.contains(pos)) { - return; - } - - visited.add(pos); - - if (editSession.getBlock(pos).getType() == initialType) { - editSession.setBlock(pos, pattern.next(pos)); - } else { - return; - } - - recurse(server, editSession, world, pos.add(1, 0, 0).toBlockVector(), - origin, size, initialType, visited); - recurse(server, editSession, world, pos.add(-1, 0, 0).toBlockVector(), - origin, size, initialType, visited); - recurse(server, editSession, world, pos.add(0, 0, 1).toBlockVector(), - origin, size, initialType, visited); - recurse(server, editSession, world, pos.add(0, 0, -1).toBlockVector(), - origin, size, initialType, visited); - recurse(server, editSession, world, pos.add(0, 1, 0).toBlockVector(), - origin, size, initialType, visited); - recurse(server, editSession, world, pos.add(0, -1, 0).toBlockVector(), - origin, size, initialType, visited); - } - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command.tool; + +import java.util.HashSet; +import java.util.Set; +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.blocks.BlockID; +import com.sk89q.worldedit.patterns.Pattern; + +/** + * A tool that flood fills blocks. + * + * @author sk89q + */ +public class FloodFillTool implements BlockTool { + private int range; + private Pattern pattern; + + public FloodFillTool(int range, Pattern pattern) { + this.range = range; + this.pattern = pattern; + } + + public boolean canUse(LocalPlayer player) { + return player.hasPermission("worldedit.tool.flood-fill"); + } + + public boolean actPrimary(ServerInterface server, LocalConfiguration config, + LocalPlayer player, LocalSession session, WorldVector clicked) { + LocalWorld world = clicked.getWorld(); + + int initialType = world.getBlockType(clicked); + + if (initialType == BlockID.AIR) { + return true; + } + + if (initialType == BlockID.BEDROCK && !player.canDestroyBedrock()) { + return true; + } + + EditSession editSession = session.createEditSession(player); + + try { + recurse(server, editSession, world, clicked.toBlockVector(), + clicked, range, initialType, new HashSet()); + } catch (MaxChangedBlocksException e) { + player.printError("Max blocks change limit reached."); + } finally { + session.remember(editSession); + } + + return true; + } + + /** + * Helper method. + * + * @param server + * @param superPickaxeManyDrop + * @param world + * @param pos + * @param origin + * @param size + * @param initialType + * @param visited + */ + private void recurse(ServerInterface server, EditSession editSession, + LocalWorld world, BlockVector pos, + Vector origin, int size, int initialType, + Set visited) + throws MaxChangedBlocksException { + + if (origin.distance(pos) > size || visited.contains(pos)) { + return; + } + + visited.add(pos); + + if (editSession.getBlock(pos).getType() == initialType) { + editSession.setBlock(pos, pattern.next(pos)); + } else { + return; + } + + recurse(server, editSession, world, pos.add(1, 0, 0).toBlockVector(), + origin, size, initialType, visited); + recurse(server, editSession, world, pos.add(-1, 0, 0).toBlockVector(), + origin, size, initialType, visited); + recurse(server, editSession, world, pos.add(0, 0, 1).toBlockVector(), + origin, size, initialType, visited); + recurse(server, editSession, world, pos.add(0, 0, -1).toBlockVector(), + origin, size, initialType, visited); + recurse(server, editSession, world, pos.add(0, 1, 0).toBlockVector(), + origin, size, initialType, visited); + recurse(server, editSession, world, pos.add(0, -1, 0).toBlockVector(), + origin, size, initialType, visited); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/tools/LongRangeBuildTool.java b/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/tools/LongRangeBuildTool.java rename to src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java index ade228f06..53d80859a 100644 --- a/src/main/java/com/sk89q/worldedit/tools/LongRangeBuildTool.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java @@ -1,98 +1,98 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.tools; - -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.blocks.BlockID; - -/** - * A tool that can place (or remove) blocks at a distance. - * - * @author wizjany - */ -public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTool { - - BaseBlock primary; - BaseBlock secondary; - - public LongRangeBuildTool(BaseBlock primary, BaseBlock secondary) { - super("worldedit.tool.lrbuild"); - this.primary = primary; - this.secondary = secondary; - } - - @Override - public boolean canUse(LocalPlayer player) { - return player.hasPermission("worldedit.tool.lrbuild"); - } - - public boolean actSecondary(ServerInterface server, LocalConfiguration config, - LocalPlayer player, LocalSession session) { - - WorldVectorFace pos = getTargetFace(player); - if (pos == null) return false; - EditSession eS = session.createEditSession(player); - try { - if (secondary.getType() == BlockID.AIR) { - eS.setBlock(pos, secondary); - } else { - eS.setBlock(pos.getFaceVector(), secondary); - } - return true; - } catch (MaxChangedBlocksException e) { - // one block? eat it - } - return false; - - } - - @Override - public boolean actPrimary(ServerInterface server, LocalConfiguration config, - LocalPlayer player, LocalSession session) { - - WorldVectorFace pos = getTargetFace(player); - if (pos == null) return false; - EditSession eS = session.createEditSession(player); - try { - if (primary.getType() == BlockID.AIR) { - eS.setBlock(pos, primary); - } else { - eS.setBlock(pos.getFaceVector(), primary); - } - return true; - } catch (MaxChangedBlocksException e) { - // one block? eat it - } - return false; - } - - public WorldVectorFace getTargetFace(LocalPlayer player) { - WorldVectorFace target = null; - target = player.getBlockTraceFace(getRange(), true); - - if (target == null) { - player.printError("No block in sight!"); - return null; - } - - return target; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command.tool; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockID; + +/** + * A tool that can place (or remove) blocks at a distance. + * + * @author wizjany + */ +public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTool { + + BaseBlock primary; + BaseBlock secondary; + + public LongRangeBuildTool(BaseBlock primary, BaseBlock secondary) { + super("worldedit.tool.lrbuild"); + this.primary = primary; + this.secondary = secondary; + } + + @Override + public boolean canUse(LocalPlayer player) { + return player.hasPermission("worldedit.tool.lrbuild"); + } + + public boolean actSecondary(ServerInterface server, LocalConfiguration config, + LocalPlayer player, LocalSession session) { + + WorldVectorFace pos = getTargetFace(player); + if (pos == null) return false; + EditSession eS = session.createEditSession(player); + try { + if (secondary.getType() == BlockID.AIR) { + eS.setBlock(pos, secondary); + } else { + eS.setBlock(pos.getFaceVector(), secondary); + } + return true; + } catch (MaxChangedBlocksException e) { + // one block? eat it + } + return false; + + } + + @Override + public boolean actPrimary(ServerInterface server, LocalConfiguration config, + LocalPlayer player, LocalSession session) { + + WorldVectorFace pos = getTargetFace(player); + if (pos == null) return false; + EditSession eS = session.createEditSession(player); + try { + if (primary.getType() == BlockID.AIR) { + eS.setBlock(pos, primary); + } else { + eS.setBlock(pos.getFaceVector(), primary); + } + return true; + } catch (MaxChangedBlocksException e) { + // one block? eat it + } + return false; + } + + public WorldVectorFace getTargetFace(LocalPlayer player) { + WorldVectorFace target = null; + target = player.getBlockTraceFace(getRange(), true); + + if (target == null) { + player.printError("No block in sight!"); + return null; + } + + return target; + } +} diff --git a/src/main/java/com/sk89q/worldedit/tools/QueryTool.java b/src/main/java/com/sk89q/worldedit/command/tool/QueryTool.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/tools/QueryTool.java rename to src/main/java/com/sk89q/worldedit/command/tool/QueryTool.java index 5621520a7..e66fe6e89 100644 --- a/src/main/java/com/sk89q/worldedit/tools/QueryTool.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/QueryTool.java @@ -1,65 +1,65 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.tools; - -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.blocks.*; - -/** - * Plants a tree. - * - * @author sk89q - */ -public class QueryTool implements BlockTool { - - public boolean canUse(LocalPlayer player) { - return player.hasPermission("worldedit.tool.info"); - } - - public boolean actPrimary(ServerInterface server, LocalConfiguration config, - LocalPlayer player, LocalSession session, WorldVector clicked) { - - LocalWorld world = clicked.getWorld(); - EditSession editSession = WorldEdit.getInstance().getEditSessionFactory().getEditSession(world, 0, player); - BaseBlock block = (editSession).rawGetBlock(clicked); - BlockType type = BlockType.fromID(block.getType()); - - player.print("\u00A79@" + clicked + ": " + "\u00A7e" - + "#" + block.getType() + "\u00A77" + " (" - + (type == null ? "Unknown" : type.getName()) + ") " - + "\u00A7f" - + "[" + block.getData() + "]" + " (" + world.getBlockLightLevel(clicked) + "/" + world.getBlockLightLevel(clicked.add(0, 1, 0)) + ")"); - - if (block instanceof MobSpawnerBlock) { - player.printRaw("\u00A7e" + "Mob Type: " - + ((MobSpawnerBlock) block).getMobType()); - } else if (block instanceof NoteBlock) { - player.printRaw("\u00A7e" + "Note block: " - + ((NoteBlock) block).getNote()); - } else if (block.getType() == BlockID.CLOTH) { - // Should never be null - player.printRaw("\u00A7e" + "Color: " - + ClothColor.fromID(block.getData()).getName()); - } - - return true; - } - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command.tool; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.blocks.*; + +/** + * Plants a tree. + * + * @author sk89q + */ +public class QueryTool implements BlockTool { + + public boolean canUse(LocalPlayer player) { + return player.hasPermission("worldedit.tool.info"); + } + + public boolean actPrimary(ServerInterface server, LocalConfiguration config, + LocalPlayer player, LocalSession session, WorldVector clicked) { + + LocalWorld world = clicked.getWorld(); + EditSession editSession = WorldEdit.getInstance().getEditSessionFactory().getEditSession(world, 0, player); + BaseBlock block = (editSession).rawGetBlock(clicked); + BlockType type = BlockType.fromID(block.getType()); + + player.print("\u00A79@" + clicked + ": " + "\u00A7e" + + "#" + block.getType() + "\u00A77" + " (" + + (type == null ? "Unknown" : type.getName()) + ") " + + "\u00A7f" + + "[" + block.getData() + "]" + " (" + world.getBlockLightLevel(clicked) + "/" + world.getBlockLightLevel(clicked.add(0, 1, 0)) + ")"); + + if (block instanceof MobSpawnerBlock) { + player.printRaw("\u00A7e" + "Mob Type: " + + ((MobSpawnerBlock) block).getMobType()); + } else if (block instanceof NoteBlock) { + player.printRaw("\u00A7e" + "Note block: " + + ((NoteBlock) block).getNote()); + } else if (block.getType() == BlockID.CLOTH) { + // Should never be null + player.printRaw("\u00A7e" + "Color: " + + ClothColor.fromID(block.getData()).getName()); + } + + return true; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/tools/RecursivePickaxe.java b/src/main/java/com/sk89q/worldedit/command/tool/RecursivePickaxe.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/tools/RecursivePickaxe.java rename to src/main/java/com/sk89q/worldedit/command/tool/RecursivePickaxe.java index e0099d5d7..f21e9fc10 100644 --- a/src/main/java/com/sk89q/worldedit/tools/RecursivePickaxe.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/RecursivePickaxe.java @@ -1,127 +1,127 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.tools; - -import java.util.HashSet; -import java.util.Set; - -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.blocks.BlockID; - -/** - * A pickaxe mode that recursively finds adjacent blocks within range of - * an initial block and of the same type. - * - * @author sk89q - */ -public class RecursivePickaxe implements BlockTool { - private static final BaseBlock air = new BaseBlock(0); - private double range; - - public RecursivePickaxe(double range) { - this.range = range; - } - - public boolean canUse(LocalPlayer player) { - return player.hasPermission("worldedit.superpickaxe.recursive"); - } - - public boolean actPrimary(ServerInterface server, LocalConfiguration config, - LocalPlayer player, LocalSession session, WorldVector clicked) { - LocalWorld world = clicked.getWorld(); - - int initialType = world.getBlockType(clicked); - - if (initialType == BlockID.AIR) { - return true; - } - - if (initialType == BlockID.BEDROCK && !player.canDestroyBedrock()) { - return true; - } - - EditSession editSession = session.createEditSession(player); - - try { - recurse(server, editSession, world, clicked.toBlockVector(), - clicked, range, initialType, new HashSet(), - config.superPickaxeManyDrop); - } catch (MaxChangedBlocksException e) { - player.printError("Max blocks change limit reached."); - } finally { - session.remember(editSession); - } - - return true; - } - - /** - * Helper method. - * - * @param server - * @param superPickaxeManyDrop - * @param world - * @param pos - * @param origin - * @param size - * @param initialType - * @param visited - */ - private static void recurse(ServerInterface server, EditSession editSession, - LocalWorld world, BlockVector pos, - Vector origin, double size, int initialType, - Set visited, boolean drop) - throws MaxChangedBlocksException { - - final double distanceSq = origin.distanceSq(pos); - if (distanceSq > size*size || visited.contains(pos)) { - return; - } - - visited.add(pos); - - if (editSession.getBlock(pos).getType() != initialType) { - return; - } - - if (drop) { - world.simulateBlockMine(pos); - } - - world.queueBlockBreakEffect(server, pos, initialType, distanceSq); - - editSession.setBlock(pos, air); - - recurse(server, editSession, world, pos.add(1, 0, 0).toBlockVector(), - origin, size, initialType, visited, drop); - recurse(server, editSession, world, pos.add(-1, 0, 0).toBlockVector(), - origin, size, initialType, visited, drop); - recurse(server, editSession, world, pos.add(0, 0, 1).toBlockVector(), - origin, size, initialType, visited, drop); - recurse(server, editSession, world, pos.add(0, 0, -1).toBlockVector(), - origin, size, initialType, visited, drop); - recurse(server, editSession, world, pos.add(0, 1, 0).toBlockVector(), - origin, size, initialType, visited, drop); - recurse(server, editSession, world, pos.add(0, -1, 0).toBlockVector(), - origin, size, initialType, visited, drop); - } - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command.tool; + +import java.util.HashSet; +import java.util.Set; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockID; + +/** + * A pickaxe mode that recursively finds adjacent blocks within range of + * an initial block and of the same type. + * + * @author sk89q + */ +public class RecursivePickaxe implements BlockTool { + private static final BaseBlock air = new BaseBlock(0); + private double range; + + public RecursivePickaxe(double range) { + this.range = range; + } + + public boolean canUse(LocalPlayer player) { + return player.hasPermission("worldedit.superpickaxe.recursive"); + } + + public boolean actPrimary(ServerInterface server, LocalConfiguration config, + LocalPlayer player, LocalSession session, WorldVector clicked) { + LocalWorld world = clicked.getWorld(); + + int initialType = world.getBlockType(clicked); + + if (initialType == BlockID.AIR) { + return true; + } + + if (initialType == BlockID.BEDROCK && !player.canDestroyBedrock()) { + return true; + } + + EditSession editSession = session.createEditSession(player); + + try { + recurse(server, editSession, world, clicked.toBlockVector(), + clicked, range, initialType, new HashSet(), + config.superPickaxeManyDrop); + } catch (MaxChangedBlocksException e) { + player.printError("Max blocks change limit reached."); + } finally { + session.remember(editSession); + } + + return true; + } + + /** + * Helper method. + * + * @param server + * @param superPickaxeManyDrop + * @param world + * @param pos + * @param origin + * @param size + * @param initialType + * @param visited + */ + private static void recurse(ServerInterface server, EditSession editSession, + LocalWorld world, BlockVector pos, + Vector origin, double size, int initialType, + Set visited, boolean drop) + throws MaxChangedBlocksException { + + final double distanceSq = origin.distanceSq(pos); + if (distanceSq > size*size || visited.contains(pos)) { + return; + } + + visited.add(pos); + + if (editSession.getBlock(pos).getType() != initialType) { + return; + } + + if (drop) { + world.simulateBlockMine(pos); + } + + world.queueBlockBreakEffect(server, pos, initialType, distanceSq); + + editSession.setBlock(pos, air); + + recurse(server, editSession, world, pos.add(1, 0, 0).toBlockVector(), + origin, size, initialType, visited, drop); + recurse(server, editSession, world, pos.add(-1, 0, 0).toBlockVector(), + origin, size, initialType, visited, drop); + recurse(server, editSession, world, pos.add(0, 0, 1).toBlockVector(), + origin, size, initialType, visited, drop); + recurse(server, editSession, world, pos.add(0, 0, -1).toBlockVector(), + origin, size, initialType, visited, drop); + recurse(server, editSession, world, pos.add(0, 1, 0).toBlockVector(), + origin, size, initialType, visited, drop); + recurse(server, editSession, world, pos.add(0, -1, 0).toBlockVector(), + origin, size, initialType, visited, drop); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/tools/SinglePickaxe.java b/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/tools/SinglePickaxe.java rename to src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java index 67d269083..3e2a47de9 100644 --- a/src/main/java/com/sk89q/worldedit/tools/SinglePickaxe.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java @@ -1,57 +1,57 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.tools; - -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.blocks.BlockID; - -/** - * A super pickaxe mode that removes one block. - * - * @author sk89q - */ -public class SinglePickaxe implements BlockTool { - - public boolean canUse(LocalPlayer player) { - return player.hasPermission("worldedit.superpickaxe"); - } - - public boolean actPrimary(ServerInterface server, LocalConfiguration config, - LocalPlayer player, LocalSession session, WorldVector clicked) { - LocalWorld world = clicked.getWorld(); - - final int blockType = world.getBlockType(clicked); - if (blockType == BlockID.BEDROCK - && !player.canDestroyBedrock()) { - return true; - } - - if (config.superPickaxeDrop) { - world.simulateBlockMine(clicked); - } - - world.setBlockType(clicked, BlockID.AIR); - - world.playEffect(clicked, 2001, blockType); - - return true; - } - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command.tool; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.blocks.BlockID; + +/** + * A super pickaxe mode that removes one block. + * + * @author sk89q + */ +public class SinglePickaxe implements BlockTool { + + public boolean canUse(LocalPlayer player) { + return player.hasPermission("worldedit.superpickaxe"); + } + + public boolean actPrimary(ServerInterface server, LocalConfiguration config, + LocalPlayer player, LocalSession session, WorldVector clicked) { + LocalWorld world = clicked.getWorld(); + + final int blockType = world.getBlockType(clicked); + if (blockType == BlockID.BEDROCK + && !player.canDestroyBedrock()) { + return true; + } + + if (config.superPickaxeDrop) { + world.simulateBlockMine(clicked); + } + + world.setBlockType(clicked, BlockID.AIR); + + world.playEffect(clicked, 2001, blockType); + + return true; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/tools/Tool.java b/src/main/java/com/sk89q/worldedit/command/tool/Tool.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/tools/Tool.java rename to src/main/java/com/sk89q/worldedit/command/tool/Tool.java index c20bf2b0d..aae350a51 100644 --- a/src/main/java/com/sk89q/worldedit/tools/Tool.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/Tool.java @@ -1,41 +1,41 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.tools; - -import com.sk89q.worldedit.LocalPlayer; - -/** - * Represents a tool. This interface alone defines nothing. A tool also - * has to implement BlockTool or TraceTool. - * - * @author sk89q - */ -public abstract interface Tool { - - /** - * Checks to see if the player can still be using this tool (considering - * permissions and such). - * - * @param player - * @return - */ - public boolean canUse(LocalPlayer player); - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.command.tool; + +import com.sk89q.worldedit.LocalPlayer; + +/** + * Represents a tool. This interface alone defines nothing. A tool also + * has to implement BlockTool or TraceTool. + * + * @author sk89q + */ +public abstract interface Tool { + + /** + * Checks to see if the player can still be using this tool (considering + * permissions and such). + * + * @param player + * @return + */ + public boolean canUse(LocalPlayer player); + +} diff --git a/src/main/java/com/sk89q/worldedit/tools/TraceTool.java b/src/main/java/com/sk89q/worldedit/command/tool/TraceTool.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/tools/TraceTool.java rename to src/main/java/com/sk89q/worldedit/command/tool/TraceTool.java index 85e909c2d..c36a17eed 100644 --- a/src/main/java/com/sk89q/worldedit/tools/TraceTool.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/TraceTool.java @@ -1,45 +1,45 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.tools; - -import com.sk89q.worldedit.LocalConfiguration; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.ServerInterface; - -/** - * Represents a tool that does not require a block. - * - * @author sk89q - */ -public interface TraceTool extends Tool { - /** - * Perform the action. Should return true to deny the default - * action. - * - * @param server - * @param config - * @param player - * @param session - * @return true to deny - */ - public boolean actPrimary(ServerInterface server, LocalConfiguration config, - LocalPlayer player, LocalSession session); -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.command.tool; + +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.ServerInterface; + +/** + * Represents a tool that does not require a block. + * + * @author sk89q + */ +public interface TraceTool extends Tool { + /** + * Perform the action. Should return true to deny the default + * action. + * + * @param server + * @param config + * @param player + * @param session + * @return true to deny + */ + public boolean actPrimary(ServerInterface server, LocalConfiguration config, + LocalPlayer player, LocalSession session); +} diff --git a/src/main/java/com/sk89q/worldedit/tools/TreePlanter.java b/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/tools/TreePlanter.java rename to src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java index 7842dfcc1..4fdc5c235 100644 --- a/src/main/java/com/sk89q/worldedit/tools/TreePlanter.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java @@ -1,68 +1,68 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.tools; - -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.util.TreeGenerator; - -/** - * Plants a tree. - * - * @author sk89q - */ -public class TreePlanter implements BlockTool { - private TreeGenerator gen; - - public TreePlanter(TreeGenerator gen) { - this.gen = gen; - } - - public boolean canUse(LocalPlayer player) { - return player.hasPermission("worldedit.tool.tree"); - } - - public boolean actPrimary(ServerInterface server, LocalConfiguration config, - LocalPlayer player, LocalSession session, WorldVector clicked) { - - EditSession editSession = session.createEditSession(player); - - try { - boolean successful = false; - - for (int i = 0; i < 10; i++) { - if (gen.generate(editSession, clicked.add(0, 1, 0))) { - successful = true; - break; - } - } - - if (!successful) { - player.printError("A tree can't go there."); - } - } catch (MaxChangedBlocksException e) { - player.printError("Max. blocks changed reached."); - } finally { - session.remember(editSession); - } - - return true; - } - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.command.tool; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.util.TreeGenerator; + +/** + * Plants a tree. + * + * @author sk89q + */ +public class TreePlanter implements BlockTool { + private TreeGenerator gen; + + public TreePlanter(TreeGenerator gen) { + this.gen = gen; + } + + public boolean canUse(LocalPlayer player) { + return player.hasPermission("worldedit.tool.tree"); + } + + public boolean actPrimary(ServerInterface server, LocalConfiguration config, + LocalPlayer player, LocalSession session, WorldVector clicked) { + + EditSession editSession = session.createEditSession(player); + + try { + boolean successful = false; + + for (int i = 0; i < 10; i++) { + if (gen.generate(editSession, clicked.add(0, 1, 0))) { + successful = true; + break; + } + } + + if (!successful) { + player.printError("A tree can't go there."); + } + } catch (MaxChangedBlocksException e) { + player.printError("Max. blocks changed reached."); + } finally { + session.remember(editSession); + } + + return true; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/tools/brushes/Brush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/Brush.java similarity index 93% rename from src/main/java/com/sk89q/worldedit/tools/brushes/Brush.java rename to src/main/java/com/sk89q/worldedit/command/tool/brush/Brush.java index 187183133..ae8ff33f1 100644 --- a/src/main/java/com/sk89q/worldedit/tools/brushes/Brush.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/Brush.java @@ -1,44 +1,44 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.tools.brushes; - -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.patterns.Pattern; - -/** - * Represents a brush. - * - * @author sk89q - */ -public interface Brush { - /** - * Build the object. - * - * @param editSession - * @param pos - * @param mat - * @param size - * @throws MaxChangedBlocksException - */ - public void build(EditSession editSession, Vector pos, Pattern mat, double size) - throws MaxChangedBlocksException; -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.command.tool.brush; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.patterns.Pattern; + +/** + * Represents a brush. + * + * @author sk89q + */ +public interface Brush { + /** + * Build the object. + * + * @param editSession + * @param pos + * @param mat + * @param size + * @throws MaxChangedBlocksException + */ + public void build(EditSession editSession, Vector pos, Pattern mat, double size) + throws MaxChangedBlocksException; +} diff --git a/src/main/java/com/sk89q/worldedit/tools/brushes/ButcherBrush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/ButcherBrush.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/tools/brushes/ButcherBrush.java rename to src/main/java/com/sk89q/worldedit/command/tool/brush/ButcherBrush.java index 7e4c97c3f..bbdeeb0a9 100644 --- a/src/main/java/com/sk89q/worldedit/tools/brushes/ButcherBrush.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/ButcherBrush.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.tools.brushes; +package com.sk89q.worldedit.command.tool.brush; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; diff --git a/src/main/java/com/sk89q/worldedit/tools/brushes/ClipboardBrush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/tools/brushes/ClipboardBrush.java rename to src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java index 83b436767..7037d12b3 100644 --- a/src/main/java/com/sk89q/worldedit/tools/brushes/ClipboardBrush.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java @@ -1,41 +1,41 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.tools.brushes; - -import com.sk89q.worldedit.CuboidClipboard; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.patterns.Pattern; - -public class ClipboardBrush implements Brush { - private CuboidClipboard clipboard; - private boolean noAir; - - public ClipboardBrush(CuboidClipboard clipboard, boolean noAir) { - this.clipboard = clipboard; - this.noAir = noAir; - } - - public void build(EditSession editSession, Vector pos, Pattern mat, double size) - throws MaxChangedBlocksException { - clipboard.place(editSession, pos.subtract(clipboard.getSize().divide(2)), noAir); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.command.tool.brush; + +import com.sk89q.worldedit.CuboidClipboard; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.patterns.Pattern; + +public class ClipboardBrush implements Brush { + private CuboidClipboard clipboard; + private boolean noAir; + + public ClipboardBrush(CuboidClipboard clipboard, boolean noAir) { + this.clipboard = clipboard; + this.noAir = noAir; + } + + public void build(EditSession editSession, Vector pos, Pattern mat, double size) + throws MaxChangedBlocksException { + clipboard.place(editSession, pos.subtract(clipboard.getSize().divide(2)), noAir); + } +} diff --git a/src/main/java/com/sk89q/worldedit/tools/brushes/CylinderBrush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/CylinderBrush.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/tools/brushes/CylinderBrush.java rename to src/main/java/com/sk89q/worldedit/command/tool/brush/CylinderBrush.java index 400583261..c5ca176c5 100644 --- a/src/main/java/com/sk89q/worldedit/tools/brushes/CylinderBrush.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/CylinderBrush.java @@ -1,38 +1,38 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.tools.brushes; - -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.patterns.Pattern; - -public class CylinderBrush implements Brush { - private int height; - - public CylinderBrush(int height) { - this.height = height; - } - - public void build(EditSession editSession, Vector pos, Pattern mat, double size) - throws MaxChangedBlocksException { - editSession.makeCylinder(pos, mat, size, size, height, true); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.command.tool.brush; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.patterns.Pattern; + +public class CylinderBrush implements Brush { + private int height; + + public CylinderBrush(int height) { + this.height = height; + } + + public void build(EditSession editSession, Vector pos, Pattern mat, double size) + throws MaxChangedBlocksException { + editSession.makeCylinder(pos, mat, size, size, height, true); + } +} diff --git a/src/main/java/com/sk89q/worldedit/tools/brushes/GravityBrush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java similarity index 98% rename from src/main/java/com/sk89q/worldedit/tools/brushes/GravityBrush.java rename to src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java index 4786838e3..caeaed2e6 100644 --- a/src/main/java/com/sk89q/worldedit/tools/brushes/GravityBrush.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.tools.brushes; +package com.sk89q.worldedit.command.tool.brush; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; diff --git a/src/main/java/com/sk89q/worldedit/tools/brushes/HollowCylinderBrush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowCylinderBrush.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/tools/brushes/HollowCylinderBrush.java rename to src/main/java/com/sk89q/worldedit/command/tool/brush/HollowCylinderBrush.java index 7127e797d..30e4cc602 100644 --- a/src/main/java/com/sk89q/worldedit/tools/brushes/HollowCylinderBrush.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowCylinderBrush.java @@ -1,38 +1,38 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.tools.brushes; - -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.patterns.Pattern; - -public class HollowCylinderBrush implements Brush { - private int height; - - public HollowCylinderBrush(int height) { - this.height = height; - } - - public void build(EditSession editSession, Vector pos, Pattern mat, double size) - throws MaxChangedBlocksException { - editSession.makeCylinder(pos, mat, size, size, height, false); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.command.tool.brush; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.patterns.Pattern; + +public class HollowCylinderBrush implements Brush { + private int height; + + public HollowCylinderBrush(int height) { + this.height = height; + } + + public void build(EditSession editSession, Vector pos, Pattern mat, double size) + throws MaxChangedBlocksException { + editSession.makeCylinder(pos, mat, size, size, height, false); + } +} diff --git a/src/main/java/com/sk89q/worldedit/tools/brushes/HollowSphereBrush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowSphereBrush.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/tools/brushes/HollowSphereBrush.java rename to src/main/java/com/sk89q/worldedit/command/tool/brush/HollowSphereBrush.java index c7328f012..c9ca5f04d 100644 --- a/src/main/java/com/sk89q/worldedit/tools/brushes/HollowSphereBrush.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowSphereBrush.java @@ -1,35 +1,35 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.tools.brushes; - -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.patterns.Pattern; - -public class HollowSphereBrush implements Brush { - public HollowSphereBrush() { - } - - public void build(EditSession editSession, Vector pos, Pattern mat, double size) - throws MaxChangedBlocksException { - editSession.makeSphere(pos, mat, size, size, size, false); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.command.tool.brush; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.patterns.Pattern; + +public class HollowSphereBrush implements Brush { + public HollowSphereBrush() { + } + + public void build(EditSession editSession, Vector pos, Pattern mat, double size) + throws MaxChangedBlocksException { + editSession.makeSphere(pos, mat, size, size, size, false); + } +} diff --git a/src/main/java/com/sk89q/worldedit/tools/brushes/SmoothBrush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/SmoothBrush.java similarity index 89% rename from src/main/java/com/sk89q/worldedit/tools/brushes/SmoothBrush.java rename to src/main/java/com/sk89q/worldedit/command/tool/brush/SmoothBrush.java index cd8bde553..973621a97 100644 --- a/src/main/java/com/sk89q/worldedit/tools/brushes/SmoothBrush.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/SmoothBrush.java @@ -1,56 +1,56 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.tools.brushes; - -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.HeightMap; -import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.WorldVector; -import com.sk89q.worldedit.filtering.GaussianKernel; -import com.sk89q.worldedit.filtering.HeightMapFilter; -import com.sk89q.worldedit.patterns.Pattern; -import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.regions.Region; - -public class SmoothBrush implements Brush { - private int iterations; - private boolean naturalOnly; - - public SmoothBrush(int iterations) { - this(iterations, false); - } - - public SmoothBrush(int iterations, boolean naturalOnly) { - this.iterations = iterations; - this.naturalOnly = naturalOnly; - } - - public void build(EditSession editSession, Vector pos, Pattern mat, double size) - throws MaxChangedBlocksException { - double rad = size; - WorldVector min = new WorldVector(editSession.getWorld(), pos.subtract(rad, rad, rad)); - Vector max = pos.add(rad, rad + 10, rad); - Region region = new CuboidRegion(editSession.getWorld(), min, max); - HeightMap heightMap = new HeightMap(editSession, region, naturalOnly); - HeightMapFilter filter = new HeightMapFilter(new GaussianKernel(5, 1.0)); - heightMap.applyFilter(filter, iterations); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.command.tool.brush; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.math.convolution.HeightMap; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldVector; +import com.sk89q.worldedit.math.convolution.GaussianKernel; +import com.sk89q.worldedit.math.convolution.HeightMapFilter; +import com.sk89q.worldedit.patterns.Pattern; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; + +public class SmoothBrush implements Brush { + private int iterations; + private boolean naturalOnly; + + public SmoothBrush(int iterations) { + this(iterations, false); + } + + public SmoothBrush(int iterations, boolean naturalOnly) { + this.iterations = iterations; + this.naturalOnly = naturalOnly; + } + + public void build(EditSession editSession, Vector pos, Pattern mat, double size) + throws MaxChangedBlocksException { + double rad = size; + WorldVector min = new WorldVector(editSession.getWorld(), pos.subtract(rad, rad, rad)); + Vector max = pos.add(rad, rad + 10, rad); + Region region = new CuboidRegion(editSession.getWorld(), min, max); + HeightMap heightMap = new HeightMap(editSession, region, naturalOnly); + HeightMapFilter filter = new HeightMapFilter(new GaussianKernel(5, 1.0)); + heightMap.applyFilter(filter, iterations); + } +} diff --git a/src/main/java/com/sk89q/worldedit/tools/brushes/SphereBrush.java b/src/main/java/com/sk89q/worldedit/command/tool/brush/SphereBrush.java similarity index 93% rename from src/main/java/com/sk89q/worldedit/tools/brushes/SphereBrush.java rename to src/main/java/com/sk89q/worldedit/command/tool/brush/SphereBrush.java index e3f29f26c..aa09018d1 100644 --- a/src/main/java/com/sk89q/worldedit/tools/brushes/SphereBrush.java +++ b/src/main/java/com/sk89q/worldedit/command/tool/brush/SphereBrush.java @@ -1,35 +1,35 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.tools.brushes; - -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.patterns.Pattern; - -public class SphereBrush implements Brush { - public SphereBrush() { - } - - public void build(EditSession editSession, Vector pos, Pattern mat, double size) - throws MaxChangedBlocksException { - editSession.makeSphere(pos, mat, size, size, size, true); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.command.tool.brush; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.patterns.Pattern; + +public class SphereBrush implements Brush { + public SphereBrush() { + } + + public void build(EditSession editSession, Vector pos, Pattern mat, double size) + throws MaxChangedBlocksException { + editSession.makeSphere(pos, mat, size, size, size, true); + } +} diff --git a/src/main/java/com/sk89q/worldedit/event/Event.java b/src/main/java/com/sk89q/worldedit/event/Event.java new file mode 100644 index 000000000..0691391e2 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/event/Event.java @@ -0,0 +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 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.event; + +import com.sk89q.worldedit.util.eventbus.EventBus; + +/** + * An abstract base class for all WorldEdit events. + */ +public abstract class Event { +} diff --git a/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java b/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java new file mode 100644 index 000000000..579b14e17 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java @@ -0,0 +1,150 @@ +/* + * 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.event.extent; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.event.Event; +import com.sk89q.worldedit.extent.Extent; + +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.EditSession.Stage; + +/** + * Raised (several times) when a new {@link EditSession} is being instantiated. + *

+ * Block loggers, as well as block set interceptors, can use this event to wrap + * the given {@link Extent} with their own, which would allow them to intercept + * all changes made to the world. For example, the code below would wrap the + * existing extent with a custom one, and the custom extent would receive + * all method calls before the extent fetched from + * {@link #getExtent()} would. + *
+ * event.setExtent(new MyExtent(event.getExtent())
+ * 
+ * This event is fired several times during the creation of a single + * {@link EditSession}, but {@link #getStage()} will differ each time. + * The stage determines at which point {@link Extent}s added to this event + * will be called. For example, if you inject an extent when the stage + * is set to {@link Stage#BEFORE_HISTORY}, then you can drop (or log) changes + * before the change has reached the history, reordering, and actual change + * extents, but that means that any changes made with + * {@link EditSession#rawSetBlock(Vector, BaseBlock)} will skip your + * custom {@link Extent} because that method bypasses history (and reorder). + * It is thus recommended that loggers intercept at {@link Stage#BEFORE_CHANGE} + * and block interceptors intercept at BOTH {@link Stage#BEFORE_CHANGE} and + * {@link Stage#BEFORE_HISTORY}. + */ +public class EditSessionEvent extends Event { + + private final LocalWorld world; + private final LocalPlayer player; + private final int maxBlocks; + private final Stage stage; + private Extent extent; + + /** + * Create a new event. + * + * @param world the world + * @param player the player, or null if not available + * @param maxBlocks the maximum number of block changes + * @param stage the stage + */ + public EditSessionEvent(LocalWorld world, LocalPlayer player, int maxBlocks, Stage stage) { + checkNotNull(world); + this.world = world; + this.player = player; + this.maxBlocks = maxBlocks; + this.stage = stage; + } + + /** + * Get the player for this event. + * + * @return the player, which may be null if unavailable + */ + public @Nullable LocalPlayer getPlayer() { + return player; + } + + /** + * Get the world. + * + * @return the world + */ + public LocalWorld getWorld() { + return world; + } + + /** + * Get the maximum number of blocks that may be set. + * + * @return the maximum number of blocks, which is -1 if unlimited + */ + public int getMaxBlocks() { + return maxBlocks; + } + + /** + * Get the {@link Extent} that can be wrapped. + * + * @return the extent + */ + public Extent getExtent() { + return extent; + } + + /** + * Get the stage that is being wrapped. + * + * @return the stage + */ + public Stage getStage() { + return stage; + } + + /** + * Set a new extent that should be used. It should wrap the extent + * returned from {@link #getExtent()}. + * + * @param extent the extent + */ + public void setExtent(Extent extent) { + checkNotNull(extent); + this.extent = extent; + } + + /** + * Create a clone of this event with the given stage. + * + * @param stage the stage + * @return a new event + */ + public EditSessionEvent clone(Stage stage) { + return new EditSessionEvent(world, player, maxBlocks, stage); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/input/DisallowedUsageException.java b/src/main/java/com/sk89q/worldedit/extension/input/DisallowedUsageException.java new file mode 100644 index 000000000..13e48ff73 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/input/DisallowedUsageException.java @@ -0,0 +1,46 @@ +/* + * 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.extension.input; + +/** + * Thrown when usage is disallowed. + */ +public class DisallowedUsageException extends InputParseException { + + /** + * Create with a message. + * + * @param message the message + */ + public DisallowedUsageException(String message) { + super(message); + } + + /** + * Create with a message and a cause. + * + * @param message the message + * @param cause the cause + */ + public DisallowedUsageException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/input/InputParseException.java b/src/main/java/com/sk89q/worldedit/extension/input/InputParseException.java new file mode 100644 index 000000000..8f0980531 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/input/InputParseException.java @@ -0,0 +1,48 @@ +/* + * 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.extension.input; + +import com.sk89q.worldedit.WorldEditException; + +/** + * Thrown when parsed input results in an error. + */ +public class InputParseException extends WorldEditException { + + /** + * Throw with a message. + * + * @param message the message + */ + public InputParseException(String message) { + super(message); + } + + /** + * Throw with a message and a cause. + * + * @param message the message + * @param cause the cause + */ + public InputParseException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/input/NoMatchException.java b/src/main/java/com/sk89q/worldedit/extension/input/NoMatchException.java new file mode 100644 index 000000000..2fcc67f82 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/input/NoMatchException.java @@ -0,0 +1,46 @@ +/* + * 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.extension.input; + +/** + * Thrown when a match fails when input is parsed. + */ +public class NoMatchException extends InputParseException { + + /** + * Create with a message. + * + * @param message the message + */ + public NoMatchException(String message) { + super(message); + } + + /** + * Create with a message and a cause. + * + * @param message the message + * @param cause the cause + */ + public NoMatchException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java b/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java new file mode 100644 index 000000000..cf3f7e56d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java @@ -0,0 +1,211 @@ +/* + * 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.extension.input; + +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.extension.registry.MaskRegistry; +import com.sk89q.worldedit.extent.Extent; + +import javax.annotation.Nullable; + +/** + * Contains contextual information that may be useful when constructing + * objects from a registry (such as {@link MaskRegistry}). + *

+ * By default, {@link #isRestricted()} will return true. + */ +public class ParserContext { + + private @Nullable Extent extent; + private @Nullable LocalSession session; + private @Nullable LocalWorld world; + private @Nullable LocalPlayer player; + private boolean restricted = true; + private boolean preferringWildcard; + + /** + * Get the {@link Extent} set on this context. + * + * @return an extent + */ + public @Nullable Extent getExtent() { + return extent; + } + + /** + * Set the extent. + * + * @param extent an extent, or null if none is available + */ + public void setExtent(@Nullable Extent extent) { + this.extent = extent; + } + + /** + * Get the {@link LocalSession}. + * + * @return a session + */ + public @Nullable LocalSession getSession() { + return session; + } + + /** + * Set the session. + * + * @param session a session, or null if none is available + */ + public void setSession(@Nullable LocalSession session) { + this.session = session; + } + + /** + * Get the {@link LocalWorld} set on this context. + * + * @return a world + */ + public @Nullable LocalWorld getWorld() { + return world; + } + + /** + * Set the world. + * + * @param world a world, or null if none is available + */ + public void setWorld(@Nullable LocalWorld world) { + this.world = world; + } + + /** + * Get the {@link LocalPlayer} set on this context. + * + * @return a player + */ + public @Nullable LocalPlayer getPlayer() { + return player; + } + + /** + * Set the player. + * + * @param player a player, or null if none is available + */ + public void setPlayer(@Nullable LocalPlayer player) { + this.player = player; + } + + /** + * Get the {@link Extent} set on this context. + * + * @return an extent + * @throws InputParseException thrown if no {@link Extent} is set + */ + public Extent requireExtent() throws InputParseException { + Extent extent = getExtent(); + if (extent == null) { + throw new InputParseException("No Extent is known"); + } + return extent; + } + + /** + * Get the {@link LocalSession}. + * + * @return a session + * @throws InputParseException thrown if no {@link LocalSession} is set + */ + public LocalSession requireSession() throws InputParseException { + LocalSession session = getSession(); + if (session == null) { + throw new InputParseException("No LocalSession is known"); + } + return session; + } + + /** + * Get the {@link LocalWorld} set on this context. + * + * @return a world + * @throws InputParseException thrown if no {@link LocalWorld} is set + */ + public LocalWorld requireWorld() throws InputParseException { + LocalWorld world = getWorld(); + if (world == null) { + throw new InputParseException("No world is known"); + } + return world; + } + + /** + * Get the {@link LocalPlayer} set on this context. + * + * @return a player + * @throws InputParseException thrown if no {@link LocalPlayer} is set + */ + public LocalPlayer requirePlayer() throws InputParseException { + LocalPlayer player = getPlayer(); + if (player == null) { + throw new InputParseException("No player is known"); + } + return player; + } + + /** + * Returns whether there should be restrictions (as a result of + * limits or permissions) considered when parsing the input. + * + * @return true if restricted + */ + public boolean isRestricted() { + return restricted; + } + + /** + * Set whether there should be restrictions (as a result of + * limits or permissions) considered when parsing the input. + * + * @param restricted true if restricted + */ + public void setRestricted(boolean restricted) { + this.restricted = restricted; + } + + /** + * Get whether wildcards are preferred. + * + * @return true if wildcards are preferred + */ + public boolean isPreferringWildcard() { + return preferringWildcard; + } + + /** + * Set whether wildcards are preferred. + * + * @param preferringWildcard true if wildcards are preferred + */ + public void setPreferringWildcard(boolean preferringWildcard) { + this.preferringWildcard = preferringWildcard; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/registry/BlockRegistry.java b/src/main/java/com/sk89q/worldedit/extension/registry/BlockRegistry.java new file mode 100644 index 000000000..c1b6c611b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/registry/BlockRegistry.java @@ -0,0 +1,67 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.extension.registry; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.internal.registry.AbstractRegistry; + +import java.util.HashSet; +import java.util.Set; + +/** + * A registry of known {@link BaseBlock}s. Provides methods to instantiate + * new blocks from input. + *

+ * Instances of this class can be taken from + * {@link WorldEdit#getBlockRegistry()}. + */ +public class BlockRegistry extends AbstractRegistry { + + /** + * Create a new instance. + * + * @param worldEdit the WorldEdit instance. + */ + public BlockRegistry(WorldEdit worldEdit) { + super(worldEdit); + + parsers.add(new DefaultBlockParser(worldEdit)); + } + + /** + * Return a set of blocks from a comma-delimited list of blocks. + * + * @param input the input + * @param context the context + * @return a set of blocks + * @throws InputParseException thrown in error with the input + */ + public Set parseFromListInput(String input, ParserContext context) throws InputParseException { + Set blocks = new HashSet(); + for (String token : input.split(",")) { + blocks.add(parseFromInput(token, context)); + } + return blocks; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/registry/DefaultBlockParser.java b/src/main/java/com/sk89q/worldedit/extension/registry/DefaultBlockParser.java new file mode 100644 index 000000000..497fa3d5c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/registry/DefaultBlockParser.java @@ -0,0 +1,307 @@ +/* + * 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.extension.registry; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.blocks.*; +import com.sk89q.worldedit.extension.input.DisallowedUsageException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.NoMatchException; +import com.sk89q.worldedit.internal.registry.InputParser; + +/** + * Parses block input strings. + */ +class DefaultBlockParser extends InputParser { + + protected DefaultBlockParser(WorldEdit worldEdit) { + super(worldEdit); + } + + private static BaseBlock getBlockInHand(LocalPlayer player) throws InputParseException { + try { + return player.getBlockInHand(); + } catch (NotABlockException e) { + throw new InputParseException("You're not holding a block!"); + } catch (WorldEditException e) { + throw new InputParseException("Unknown error occurred: " + e.getMessage(), e); + } + } + + @Override + public BaseBlock parseFromInput(String input, ParserContext context) throws InputParseException { + BlockType blockType; + input = input.replace("_", " "); + input = input.replace(";", "|"); + String[] blockAndExtraData = input.split("\\|"); + String[] typeAndData = blockAndExtraData[0].split(":", 2); + String testID = typeAndData[0]; + + int blockId = -1; + + int data = -1; + + boolean parseDataValue = true; + + if ("hand".equalsIgnoreCase(testID)) { + // Get the block type from the item in the user's hand. + final BaseBlock blockInHand = getBlockInHand(context.requirePlayer()); + if (blockInHand.getClass() != BaseBlock.class) { + return blockInHand; + } + + blockId = blockInHand.getId(); + blockType = BlockType.fromID(blockId); + data = blockInHand.getData(); + } else if ("pos1".equalsIgnoreCase(testID)) { + // Get the block type from the "primary position" + final LocalWorld world = context.requireWorld(); + final BlockVector primaryPosition; + try { + primaryPosition = context.requireSession().getRegionSelector(world).getPrimaryPosition(); + } catch (IncompleteRegionException e) { + throw new InputParseException("Your selection is not complete."); + } + final BaseBlock blockInHand = world.getBlock(primaryPosition); + if (blockInHand.getClass() != BaseBlock.class) { + return blockInHand; + } + + blockId = blockInHand.getId(); + blockType = BlockType.fromID(blockId); + data = blockInHand.getData(); + } else { + // Attempt to parse the item ID or otherwise resolve an item/block + // name to its numeric ID + try { + blockId = Integer.parseInt(testID); + blockType = BlockType.fromID(blockId); + } catch (NumberFormatException e) { + blockType = BlockType.lookup(testID); + if (blockType == null) { + int t = worldEdit.getServer().resolveItem(testID); + if (t > 0) { + blockType = BlockType.fromID(t); // Could be null + blockId = t; + } + } + } + + if (blockId == -1 && blockType == null) { + // Maybe it's a cloth + ClothColor col = ClothColor.lookup(testID); + if (col == null) { + throw new NoMatchException("Unknown wool color '" + input + "'"); + } + + blockType = BlockType.CLOTH; + data = col.getID(); + + // Prevent overriding the data value + parseDataValue = false; + } + + // Read block ID + if (blockId == -1) { + blockId = blockType.getID(); + } + + if (!context.requireWorld().isValidBlockType(blockId)) { + throw new NoMatchException("Does not match a valid block type: '" + input + "'"); + } + } + + if (!context.isPreferringWildcard() && data == -1) { + // No wildcards allowed => eliminate them. + data = 0; + } + + if (parseDataValue) { // Block data not yet detected + // Parse the block data (optional) + try { + if (typeAndData.length > 1 && typeAndData[1].length() > 0) { + data = Integer.parseInt(typeAndData[1]); + } + + if (data > 15) { + throw new NoMatchException("Invalid data value '" + typeAndData[1] + "'"); + } + + if (data < 0 && (context.isRestricted() || data != -1)) { + data = 0; + } + } catch (NumberFormatException e) { + if (blockType == null) { + throw new NoMatchException("Unknown data value '" + typeAndData[1] + "'"); + } + + switch (blockType) { + case CLOTH: + case STAINED_CLAY: + case CARPET: + ClothColor col = ClothColor.lookup(typeAndData[1]); + if (col == null) { + throw new NoMatchException("Unknown wool color '" + typeAndData[1] + "'"); + } + + data = col.getID(); + break; + + case STEP: + case DOUBLE_STEP: + BlockType dataType = BlockType.lookup(typeAndData[1]); + + if (dataType == null) { + throw new NoMatchException("Unknown step type '" + typeAndData[1] + "'"); + } + + switch (dataType) { + case STONE: + data = 0; + break; + case SANDSTONE: + data = 1; + break; + case WOOD: + data = 2; + break; + case COBBLESTONE: + data = 3; + break; + case BRICK: + data = 4; + break; + case STONE_BRICK: + data = 5; + break; + case NETHER_BRICK: + data = 6; + break; + case QUARTZ_BLOCK: + data = 7; + break; + + default: + throw new NoMatchException("Invalid step type '" + typeAndData[1] + "'"); + } + break; + + default: + throw new NoMatchException("Unknown data value '" + typeAndData[1] + "'"); + } + } + } + + // Check if the item is allowed + LocalPlayer player = context.requirePlayer(); + if (context.isRestricted() && player != null && !player.hasPermission("worldedit.anyblock") + && worldEdit.getConfiguration().disallowedBlocks.contains(blockId)) { + throw new DisallowedUsageException("You are not allowed to use '" + input + "'"); + } + + if (blockType == null) { + return new BaseBlock(blockId, data); + } + + switch (blockType) { + case SIGN_POST: + case WALL_SIGN: + // Allow special sign text syntax + String[] text = new String[4]; + text[0] = blockAndExtraData.length > 1 ? blockAndExtraData[1] : ""; + text[1] = blockAndExtraData.length > 2 ? blockAndExtraData[2] : ""; + text[2] = blockAndExtraData.length > 3 ? blockAndExtraData[3] : ""; + text[3] = blockAndExtraData.length > 4 ? blockAndExtraData[4] : ""; + return new SignBlock(blockType.getID(), data, text); + + case MOB_SPAWNER: + // Allow setting mob spawn type + if (blockAndExtraData.length > 1) { + String mobName = blockAndExtraData[1]; + for (MobType mobType : MobType.values()) { + if (mobType.getName().toLowerCase().equals(mobName.toLowerCase())) { + mobName = mobType.getName(); + break; + } + } + if (!worldEdit.getServer().isValidMobType(mobName)) { + throw new NoMatchException("Unknown mob type '" + mobName + "'"); + } + return new MobSpawnerBlock(data, mobName); + } else { + return new MobSpawnerBlock(data, MobType.PIG.getName()); + } + + case NOTE_BLOCK: + // Allow setting note + if (blockAndExtraData.length <= 1) { + return new NoteBlock(data, (byte) 0); + } + + byte note = Byte.parseByte(blockAndExtraData[1]); + if (note < 0 || note > 24) { + throw new InputParseException("Out of range note value: '" + blockAndExtraData[1] + "'"); + } + + return new NoteBlock(data, note); + + case HEAD: + // allow setting type/player/rotation + if (blockAndExtraData.length <= 1) { + return new SkullBlock(data); + } + + byte rot = 0; + String type = ""; + try { + rot = Byte.parseByte(blockAndExtraData[1]); + } catch (NumberFormatException e) { + type = blockAndExtraData[1]; + if (blockAndExtraData.length > 2) { + try { + rot = Byte.parseByte(blockAndExtraData[2]); + } catch (NumberFormatException e2) { + throw new InputParseException("Second part of skull metadata should be a number."); + } + } + } + byte skullType = 0; + // type is either the mob type or the player name + // sorry for the four minecraft accounts named "skeleton", "wither", "zombie", or "creeper" + if (!type.isEmpty()) { + if (type.equalsIgnoreCase("skeleton")) skullType = 0; + else if (type.equalsIgnoreCase("wither")) skullType = 1; + else if (type.equalsIgnoreCase("zombie")) skullType = 2; + else if (type.equalsIgnoreCase("creeper")) skullType = 4; + else skullType = 3; + } + if (skullType == 3) { + return new SkullBlock(data, rot, type.replace(" ", "_")); // valid MC usernames + } else { + return new SkullBlock(data, skullType, rot); + } + + default: + return new BaseBlock(blockId, data); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/registry/DefaultMaskParser.java b/src/main/java/com/sk89q/worldedit/extension/registry/DefaultMaskParser.java new file mode 100644 index 000000000..6e0a3fd26 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/registry/DefaultMaskParser.java @@ -0,0 +1,139 @@ +/* + * 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.extension.registry; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.NoMatchException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.mask.*; +import com.sk89q.worldedit.internal.registry.InputParser; +import com.sk89q.worldedit.masks.BiomeTypeMask; +import com.sk89q.worldedit.math.noise.RandomNoise; +import com.sk89q.worldedit.session.request.Request; +import com.sk89q.worldedit.session.request.RequestSelection; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Parses mask input strings. + */ +class DefaultMaskParser extends InputParser { + + protected DefaultMaskParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Mask parseFromInput(String input, ParserContext context) throws InputParseException { + List masks = new ArrayList(); + + for (String component : input.split(" ")) { + if (component.length() == 0) { + continue; + } + + Mask current = getBlockMaskComponent(masks, component, context); + + masks.add(current); + } + + switch (masks.size()) { + case 0: + return null; + + case 1: + return masks.get(0); + + default: + return new MaskIntersection(masks); + } + } + + private Mask getBlockMaskComponent(List masks, String component, ParserContext context) throws InputParseException { + Extent extent = Request.request().getEditSession(); + + final char firstChar = component.charAt(0); + switch (firstChar) { + case '#': + if (component.equalsIgnoreCase("#existing")) { + return new ExistingBlockMask(extent); + } else if (component.equalsIgnoreCase("#solid")) { + return new SolidBlockMask(extent); + } else if (component.equalsIgnoreCase("#dregion") + || component.equalsIgnoreCase("#dselection") + || component.equalsIgnoreCase("#dsel")) { + return new RegionMask(new RequestSelection()); + } else if (component.equalsIgnoreCase("#selection") + || component.equalsIgnoreCase("#region") + || component.equalsIgnoreCase("#sel")) { + try { + return new RegionMask(context.requireSession().getSelection(context.requireWorld()).clone()); + } catch (IncompleteRegionException e) { + throw new InputParseException("Please make a selection first."); + } + } else { + throw new NoMatchException("Unrecognized mask '" + component + "'"); + } + + case '>': + case '<': + Mask submask; + if (component.length() > 1) { + submask = getBlockMaskComponent(masks, component.substring(1), context); + } else { + submask = new ExistingBlockMask(extent); + } + OffsetMask offsetMask = new OffsetMask(submask, new Vector(0, firstChar == '>' ? -1 : 1, 0)); + return new MaskIntersection(offsetMask, Masks.negate(submask)); + + case '$': + Set biomes = new HashSet(); + String[] biomesList = component.substring(1).split(","); + for (String biomeName : biomesList) { + try { + BiomeType biome = worldEdit.getServer().getBiomes().get(biomeName); + biomes.add(biome); + } catch (UnknownBiomeTypeException e) { + throw new InputParseException("Unknown biome '" + biomeName + "'"); + } + } + + return Masks.wrap(new BiomeTypeMask(biomes)); + + case '%': + int i = Integer.parseInt(component.substring(1)); + return new NoiseFilter(new RandomNoise(), ((double) i) / 100); + + case '!': + if (component.length() > 1) { + return Masks.negate(getBlockMaskComponent(masks, component.substring(1), context)); + } + + default: + return new BlockMask(extent, worldEdit.getBlockRegistry().parseFromInput(component, context)); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/registry/HashTagPatternParser.java b/src/main/java/com/sk89q/worldedit/extension/registry/HashTagPatternParser.java new file mode 100644 index 000000000..49342fe7a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/registry/HashTagPatternParser.java @@ -0,0 +1,60 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.extension.registry; + +import com.sk89q.worldedit.EmptyClipboardException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.pattern.ClipboardPattern; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.registry.InputParser; +import com.sk89q.worldedit.extension.input.InputParseException; + +class HashTagPatternParser extends InputParser { + + HashTagPatternParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Pattern parseFromInput(String input, ParserContext context) throws InputParseException { + if (input.charAt(0) == '#') { + if (!input.equals("#clipboard") && !input.equals("#copy")) { + throw new InputParseException("#clipboard or #copy is acceptable for patterns starting with #"); + } + + LocalSession session = context.requireSession(); + + if (session != null) { + try { + return new ClipboardPattern(session.getClipboard()); + } catch (EmptyClipboardException e) { + throw new InputParseException("To use #clipboard, please first copy something to your clipboard"); + } + } else { + throw new InputParseException("No session is available, so no clipboard is available"); + } + } else { + return null; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/registry/MaskRegistry.java b/src/main/java/com/sk89q/worldedit/extension/registry/MaskRegistry.java new file mode 100644 index 000000000..1a18f35a9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/registry/MaskRegistry.java @@ -0,0 +1,46 @@ +/* + * 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.extension.registry; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.internal.registry.AbstractRegistry; + +/** + * A registry of known {@link Mask}s. Provides methods to instantiate + * new masks from input. + *

+ * Instances of this class can be taken from + * {@link WorldEdit#getMaskRegistry()}. + */ +public final class MaskRegistry extends AbstractRegistry { + + /** + * Create a new mask registry. + * + * @param worldEdit the WorldEdit instance + */ + public MaskRegistry(WorldEdit worldEdit) { + super(worldEdit); + + parsers.add(new DefaultMaskParser(worldEdit)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/registry/PatternRegistry.java b/src/main/java/com/sk89q/worldedit/extension/registry/PatternRegistry.java new file mode 100644 index 000000000..d1dc569c8 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/registry/PatternRegistry.java @@ -0,0 +1,48 @@ +/* + * 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.extension.registry; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.registry.AbstractRegistry; + +/** + * A registry of known {@link Pattern}s. Provides methods to instantiate + * new patterns from input. + *

+ * Instances of this class can be taken from + * {@link WorldEdit#getPatternRegistry()}. + */ +public final class PatternRegistry extends AbstractRegistry { + + /** + * Create a new instance. + * + * @param worldEdit the WorldEdit instance + */ + public PatternRegistry(WorldEdit worldEdit) { + super(worldEdit); + + parsers.add(new HashTagPatternParser(worldEdit)); + parsers.add(new SingleBlockPatternParser(worldEdit)); + parsers.add(new RandomPatternParser(worldEdit)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extension/registry/RandomPatternParser.java b/src/main/java/com/sk89q/worldedit/extension/registry/RandomPatternParser.java new file mode 100644 index 000000000..051687f3e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/registry/RandomPatternParser.java @@ -0,0 +1,67 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.extension.registry; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.function.pattern.BlockPattern; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.function.pattern.RandomPattern; +import com.sk89q.worldedit.internal.registry.InputParser; + +class RandomPatternParser extends InputParser { + + RandomPatternParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Pattern parseFromInput(String input, ParserContext context) throws InputParseException { + BlockRegistry blockRegistry = worldEdit.getBlockRegistry(); + RandomPattern randomPattern = new RandomPattern(); + + for (String token : input.split(",")) { + BaseBlock block; + + double chance; + + // Parse special percentage syntax + if (token.matches("[0-9]+(\\.[0-9]*)?%.*")) { + String[] p = token.split("%"); + + if (p.length < 2) { + throw new InputParseException("Missing the type after the % symbol for '" + input + "'"); + } else { + chance = Double.parseDouble(p[0]); + block = blockRegistry.parseFromInput(p[1], context); + } + } else { + chance = 1; + block = blockRegistry.parseFromInput(token, context); + } + + randomPattern.add(new BlockPattern(block), chance); + } + + return randomPattern; + } +} diff --git a/src/main/java/com/sk89q/worldedit/extension/registry/SingleBlockPatternParser.java b/src/main/java/com/sk89q/worldedit/extension/registry/SingleBlockPatternParser.java new file mode 100644 index 000000000..8d527a08d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extension/registry/SingleBlockPatternParser.java @@ -0,0 +1,46 @@ +/* + * 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.extension.registry; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.pattern.BlockPattern; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.registry.InputParser; +import com.sk89q.worldedit.extension.input.InputParseException; + +class SingleBlockPatternParser extends InputParser { + + SingleBlockPatternParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Pattern parseFromInput(String input, ParserContext context) throws InputParseException { + String[] items = input.split(","); + + if (items.length == 1) { + return new BlockPattern(worldEdit.getBlockRegistry().parseFromInput(items[0], context)); + } else { + return null; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java b/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java new file mode 100644 index 000000000..1d6535f0c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java @@ -0,0 +1,102 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.extent; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.OperationQueue; + +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A base class for {@link Extent}s that merely passes extents onto another. + */ +public abstract class AbstractDelegateExtent implements Extent { + + private final Extent extent; + + /** + * Create a new instance. + * + * @param extent the extent + */ + protected AbstractDelegateExtent(Extent extent) { + checkNotNull(extent); + this.extent = extent; + } + + /** + * Get the extent. + * + * @return the extent + */ + public Extent getExtent() { + return extent; + } + + @Override + public BaseBlock getBlock(Vector position) { + return extent.getBlock(position); + } + + @Override + public BaseBlock getLazyBlock(Vector position) { + return extent.getLazyBlock(position); + } + + @Override + public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException { + return extent.setBlock(location, block); + } + + @Override + public Vector getMinimumPoint() { + return extent.getMinimumPoint(); + } + + @Override + public Vector getMaximumPoint() { + return extent.getMaximumPoint(); + } + + protected Operation commitBefore() { + return null; + } + + @Override + public final @Nullable Operation commit() { + Operation ours = commitBefore(); + Operation other = extent.commit(); + if (ours != null && other != null) { + return new OperationQueue(ours, other); + } else if (ours != null) { + return ours; + } else if (other != null) { + return other; + } else { + return null; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/ChangeSetExtent.java b/src/main/java/com/sk89q/worldedit/extent/ChangeSetExtent.java new file mode 100644 index 000000000..11d399490 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/ChangeSetExtent.java @@ -0,0 +1,56 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.extent; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.history.change.BlockChange; +import com.sk89q.worldedit.history.changeset.ChangeSet; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Stores changes to a {@link ChangeSet}. + */ +public class ChangeSetExtent extends AbstractDelegateExtent { + + private final ChangeSet changeSet; + + /** + * Create a new instance. + * + * @param extent the extent + * @param changeSet the change set + */ + public ChangeSetExtent(Extent extent, ChangeSet changeSet) { + super(extent); + checkNotNull(changeSet); + this.changeSet = changeSet; + } + + @Override + public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException { + BaseBlock previous = getBlock(location); + changeSet.add(new BlockChange(location.toBlockVector(), previous, block)); + return super.setBlock(location, block); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/Extent.java b/src/main/java/com/sk89q/worldedit/extent/Extent.java new file mode 100644 index 000000000..3fd01129a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/Extent.java @@ -0,0 +1,53 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.extent; + +import com.sk89q.worldedit.Vector; + +/** + * A world, portion of a world, clipboard, or other object that can have blocks + * set or entities placed. + * + * @see InputExtent the get____() portion + * @see OutputExtent the set____() portion + */ +public interface Extent extends InputExtent, OutputExtent { + + /** + * Get the minimum point in the extent. + *

+ * If the extent is unbounded, then a large (negative) value may + * be returned. + * + * @return the minimum point + */ + Vector getMinimumPoint(); + + /** + * Get the maximum point in the extent. + *

+ * If the extent is unbounded, then a large (positive) value may + * be returned. + * + * @return the maximum point + */ + Vector getMaximumPoint(); + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/InputExtent.java b/src/main/java/com/sk89q/worldedit/extent/InputExtent.java new file mode 100644 index 000000000..8f77fe276 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/InputExtent.java @@ -0,0 +1,76 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.extent; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.function.pattern.Pattern; + +/** + * Provides the current state of blocks, entities, and so on. + */ +public interface InputExtent { + + /** + * Get a snapshot of the block at the given location. + *

+ * If the given position is out of the bounds of the extent, then the behavior + * is undefined (an air block could be returned). However, null + * should not be returned. + *

+ * The returned block is mutable and is a snapshot of the block at the time + * of call. It has no position attached to it, so it could be reused in + * {@link Pattern}s and so on. + *

+ * Calls to this method can actually be quite expensive, so cache results + * whenever it is possible, while being aware of the mutability aspect. + * The cost, however, depends on the implementation and particular extent. + * If only basic information about the block is required, then use of + * {@link #getLazyBlock(Vector)} is recommended. + * + * @param position position of the block + * @return the block + */ + BaseBlock getBlock(Vector position); + + /** + * Get a lazy, immutable snapshot of the block at the given location that only + * immediately contains information about the block's type (and metadata). + *

+ * Further information (such as NBT data) will be available by the + * time of access. Therefore, it is not recommended that + * this method is used if the world is being simulated at the time of + * call. If the block needs to be stored for future use, then this method should + * definitely not be used. Moreover, the block that is returned is immutable (or + * should be), and therefore modifications should not be attempted on it. If a + * modifiable copy is required, then the block should be cloned. + *

+ * This method exists because it is sometimes important to inspect the block + * at a given location, but {@link #getBlock(Vector)} may be too expensive in + * the underlying implementation. It is also not possible to implement + * caching if the returned object is mutable, so this methods allows caching + * implementations to be used. + * + * @param position position of the block + * @return the block + */ + BaseBlock getLazyBlock(Vector position); + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/MaskingExtent.java b/src/main/java/com/sk89q/worldedit/extent/MaskingExtent.java new file mode 100644 index 000000000..e96a62907 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/MaskingExtent.java @@ -0,0 +1,72 @@ +/* + * 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.extent; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.function.mask.Mask; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Requires that all mutating methods pass a given {@link Mask}. + */ +public class MaskingExtent extends AbstractDelegateExtent { + + private Mask mask; + + /** + * Create a new instance. + * + * @param extent the extent + * @param mask the mask + */ + public MaskingExtent(Extent extent, Mask mask) { + super(extent); + checkNotNull(mask); + this.mask = mask; + } + + /** + * Get the mask. + * + * @return the mask + */ + public Mask getMask() { + return mask; + } + + /** + * Set a mask. + * + * @param mask a mask + */ + public void setMask(Mask mask) { + checkNotNull(mask); + this.mask = mask; + } + + @Override + public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException { + return mask.test(location) && super.setBlock(location, block); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java b/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java new file mode 100644 index 000000000..042812d8f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java @@ -0,0 +1,60 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.extent; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.function.operation.Operation; + +import javax.annotation.Nullable; + +/** + * Accepts block and entity changes. + */ +public interface OutputExtent { + + /** + * Change the block at the given location to the given block. The operation may + * not tie the given {@link BaseBlock} to the world, so future changes to the + * {@link BaseBlock} do not affect the world until this method is called again. + *

+ * The return value of this method indicates whether the change was probably + * successful. It may not be successful if, for example, the location is out + * of the bounds of the extent. It may be unsuccessful if the block passed + * is the same as the one in the world. However, the return value is only an + * estimation and it may be incorrect, but it could be used to count, for + * example, the approximate number of changes. + * + * @param position position of the block + * @param block block to set + * @return true if the block was successfully set (return value may not be accurate) + */ + boolean setBlock(Vector position, BaseBlock block) throws WorldEditException; + + /** + * Return an {@link Operation} that should be called to tie up loose ends + * (such as to commit changes in a buffer). + * + * @return an operation or null if there is none to execute + */ + @Nullable Operation commit(); + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/buffer/ForgetfulExtentBuffer.java b/src/main/java/com/sk89q/worldedit/extent/buffer/ForgetfulExtentBuffer.java new file mode 100644 index 000000000..193da9fc2 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/buffer/ForgetfulExtentBuffer.java @@ -0,0 +1,154 @@ +/* + * 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.extent.buffer; + +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockID; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.Masks; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.regions.AbstractRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionOperationException; + +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Buffers changes to an {@link Extent} and allows later retrieval for + * actual application of the changes. + *

+ * This buffer will not attempt to return results from the buffer when + * accessor methods (such as {@link #getBlock(Vector)}) are called. + */ +public class ForgetfulExtentBuffer extends AbstractDelegateExtent implements Pattern { + + private static final BaseBlock AIR = new BaseBlock(BlockID.AIR); + + private final Map buffer = new LinkedHashMap(); + private final Mask mask; + private Vector min = null; + private Vector max = null; + + /** + * Create a new extent buffer that will buffer every change. + * + * @param delegate the delegate extent for {@link Extent#getBlock(Vector)}, etc. calls + */ + public ForgetfulExtentBuffer(Extent delegate) { + this(delegate, Masks.alwaysTrue()); + } + + /** + * Create a new extent buffer that will buffer changes that meet the criteria + * of the given mask. + * + * @param delegate the delegate extent for {@link Extent#getBlock(Vector)}, etc. calls + * @param mask the mask + */ + public ForgetfulExtentBuffer(Extent delegate, Mask mask) { + super(delegate); + checkNotNull(delegate); + checkNotNull(mask); + this.mask = mask; + } + + @Override + public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException { + // Update minimum + if (min == null) { + min = location; + } else { + min = Vector.getMinimum(min, location); + } + + // Update maximum + if (max == null) { + max = location; + } else { + max = Vector.getMaximum(max, location); + } + + BlockVector blockVector = location.toBlockVector(); + if (mask.test(blockVector)) { + buffer.put(blockVector, block); + return true; + } else { + return getExtent().setBlock(location, block); + } + } + + @Override + public BaseBlock apply(Vector pos) { + BaseBlock block = buffer.get(pos.toBlockVector()); + if (block != null) { + return block; + } else { + return AIR; + } + } + + /** + * Return a region representation of this buffer. + * + * @return a region + */ + public Region asRegion() { + return new AbstractRegion(null) { + @Override + public Vector getMinimumPoint() { + return min != null ? min : new Vector(); + } + + @Override + public Vector getMaximumPoint() { + return max != null ? max : new Vector(); + } + + @Override + public void expand(Vector... changes) throws RegionOperationException { + throw new UnsupportedOperationException("Cannot change the size of this region"); + } + + @Override + public void contract(Vector... changes) throws RegionOperationException { + throw new UnsupportedOperationException("Cannot change the size of this region"); + } + + @Override + public boolean contains(Vector pt) { + return buffer.containsKey(pt.toBlockVector()); + } + + @Override + public Iterator iterator() { + return buffer.keySet().iterator(); + } + }; + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/cache/LastAccessExtentCache.java b/src/main/java/com/sk89q/worldedit/extent/cache/LastAccessExtentCache.java new file mode 100644 index 000000000..812d17674 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/cache/LastAccessExtentCache.java @@ -0,0 +1,68 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.extent.cache; + +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; + +/** + * Returns the same cached {@link BaseBlock} for repeated calls to + * {@link #getLazyBlock(Vector)} with the same position. + */ +public class LastAccessExtentCache extends AbstractDelegateExtent { + + private CachedBlock lastBlock; + + /** + * Create a new instance. + * + * @param extent the extent + */ + public LastAccessExtentCache(Extent extent) { + super(extent); + } + + @Override + public BaseBlock getLazyBlock(Vector position) { + BlockVector blockVector = position.toBlockVector(); + CachedBlock lastBlock = this.lastBlock; + if (lastBlock != null && lastBlock.position.equals(blockVector)) { + return lastBlock.block; + } else { + BaseBlock block = super.getLazyBlock(position); + this.lastBlock = new CachedBlock(blockVector, block); + return block; + } + } + + private static class CachedBlock { + private final BlockVector position; + private final BaseBlock block; + + private CachedBlock(BlockVector position, BaseBlock block) { + this.position = position; + this.block = block; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/bags/BlockBag.java b/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBag.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/bags/BlockBag.java rename to src/main/java/com/sk89q/worldedit/extent/inventory/BlockBag.java index 265d608b9..1a7a9b93f 100644 --- a/src/main/java/com/sk89q/worldedit/bags/BlockBag.java +++ b/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBag.java @@ -1,199 +1,199 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.bags; - -import com.sk89q.worldedit.WorldVector; -import com.sk89q.worldedit.blocks.*; - -/** - * Represents a source to get blocks from and store removed ones. - * - * @author sk89q - */ -public abstract class BlockBag { - /** - * Stores a block as if it was mined. - * - * @param id - * @throws BlockBagException - * @deprecated Use {@link BlockBag#storeDroppedBlock(int, int)} instead - */ - @Deprecated - public void storeDroppedBlock(int id) throws BlockBagException { - storeDroppedBlock(id, 0); - } - - /** - * Stores a block as if it was mined. - * - * @param id - * @param data - * @throws BlockBagException - */ - public void storeDroppedBlock(int id, int data) throws BlockBagException { - BaseItem dropped = BlockType.getBlockBagItem(id, data); - if (dropped == null) return; - if (dropped.getType() == BlockID.AIR) return; - - storeItem(dropped); - } - - /** - * Sets a block as if it was placed by hand. - * - * @param id - * @throws BlockBagException - * @deprecated Use {@link #fetchPlacedBlock(int,int)} instead - */ - @Deprecated - public void fetchPlacedBlock(int id) throws BlockBagException { - fetchPlacedBlock(id, 0); - } - - /** - * Sets a block as if it was placed by hand. - * - * @param id - * @param data TODO - * @throws BlockBagException - */ - public void fetchPlacedBlock(int id, int data) throws BlockBagException { - try { - // Blocks that can't be fetched... - switch (id) { - case BlockID.BEDROCK: - case BlockID.GOLD_ORE: - case BlockID.IRON_ORE: - case BlockID.COAL_ORE: - case BlockID.DIAMOND_ORE: - case BlockID.TNT: - case BlockID.MOB_SPAWNER: - case BlockID.CROPS: - case BlockID.REDSTONE_ORE: - case BlockID.GLOWING_REDSTONE_ORE: - case BlockID.SNOW: - case BlockID.LIGHTSTONE: - case BlockID.PORTAL: - throw new UnplaceableBlockException(); - - case BlockID.WATER: - case BlockID.STATIONARY_WATER: - case BlockID.LAVA: - case BlockID.STATIONARY_LAVA: - // Override liquids - return; - - default: - fetchBlock(id); - break; - } - - } catch (OutOfBlocksException e) { - BaseItem placed = BlockType.getBlockBagItem(id, data); - if (placed == null) throw e; // TODO: check - if (placed.getType() == BlockID.AIR) throw e; // TODO: check - - fetchItem(placed); - } - } - - /** - * Get a block. - * - * Either this method or fetchItem needs to be overridden - * - * @param id - * @throws BlockBagException - */ - public void fetchBlock(int id) throws BlockBagException { - fetchItem(new BaseItem(id)); - } - - /** - * Get a block. - * - * Either this method or fetchBlock needs to be overridden - * - * @param item - * @throws BlockBagException - */ - public void fetchItem(BaseItem item) throws BlockBagException { - fetchBlock(item.getType()); - } - - /** - * Store a block. - * - * Either this method or storeItem needs to be overridden - * - * @param id - * @throws BlockBagException - */ - public void storeBlock(int id) throws BlockBagException { - storeItem(new BaseItem(id)); - } - - /** - * Store a block. - * - * Either this method or storeBlock needs to be overridden - * - * @param item - * @throws BlockBagException - */ - public void storeItem(BaseItem item) throws BlockBagException { - storeBlock(item.getType()); - } - - /** - * Checks to see if a block exists without removing it. - * - * @param id - * @return whether the block exists - */ - public boolean peekBlock(int id) { - try { - fetchBlock(id); - storeBlock(id); - return true; - } catch (BlockBagException e) { - return false; - } - } - - /** - * Flush any changes. This is called at the end. - */ - public abstract void flushChanges(); - - /** - * Adds a position to be used a source. - * - * @param pos - */ - public abstract void addSourcePosition(WorldVector pos); - - /** - * Adds a position to be used a source. - * - * @param pos - */ - public abstract void addSingleSourcePosition(WorldVector pos); -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.extent.inventory; + +import com.sk89q.worldedit.WorldVector; +import com.sk89q.worldedit.blocks.*; + +/** + * Represents a source to get blocks from and store removed ones. + * + * @author sk89q + */ +public abstract class BlockBag { + /** + * Stores a block as if it was mined. + * + * @param id + * @throws BlockBagException + * @deprecated Use {@link BlockBag#storeDroppedBlock(int, int)} instead + */ + @Deprecated + public void storeDroppedBlock(int id) throws BlockBagException { + storeDroppedBlock(id, 0); + } + + /** + * Stores a block as if it was mined. + * + * @param id + * @param data + * @throws BlockBagException + */ + public void storeDroppedBlock(int id, int data) throws BlockBagException { + BaseItem dropped = BlockType.getBlockBagItem(id, data); + if (dropped == null) return; + if (dropped.getType() == BlockID.AIR) return; + + storeItem(dropped); + } + + /** + * Sets a block as if it was placed by hand. + * + * @param id + * @throws BlockBagException + * @deprecated Use {@link #fetchPlacedBlock(int,int)} instead + */ + @Deprecated + public void fetchPlacedBlock(int id) throws BlockBagException { + fetchPlacedBlock(id, 0); + } + + /** + * Sets a block as if it was placed by hand. + * + * @param id + * @param data TODO + * @throws BlockBagException + */ + public void fetchPlacedBlock(int id, int data) throws BlockBagException { + try { + // Blocks that can't be fetched... + switch (id) { + case BlockID.BEDROCK: + case BlockID.GOLD_ORE: + case BlockID.IRON_ORE: + case BlockID.COAL_ORE: + case BlockID.DIAMOND_ORE: + case BlockID.TNT: + case BlockID.MOB_SPAWNER: + case BlockID.CROPS: + case BlockID.REDSTONE_ORE: + case BlockID.GLOWING_REDSTONE_ORE: + case BlockID.SNOW: + case BlockID.LIGHTSTONE: + case BlockID.PORTAL: + throw new UnplaceableBlockException(); + + case BlockID.WATER: + case BlockID.STATIONARY_WATER: + case BlockID.LAVA: + case BlockID.STATIONARY_LAVA: + // Override liquids + return; + + default: + fetchBlock(id); + break; + } + + } catch (OutOfBlocksException e) { + BaseItem placed = BlockType.getBlockBagItem(id, data); + if (placed == null) throw e; // TODO: check + if (placed.getType() == BlockID.AIR) throw e; // TODO: check + + fetchItem(placed); + } + } + + /** + * Get a block. + * + * Either this method or fetchItem needs to be overridden + * + * @param id + * @throws BlockBagException + */ + public void fetchBlock(int id) throws BlockBagException { + fetchItem(new BaseItem(id)); + } + + /** + * Get a block. + * + * Either this method or fetchBlock needs to be overridden + * + * @param item + * @throws BlockBagException + */ + public void fetchItem(BaseItem item) throws BlockBagException { + fetchBlock(item.getType()); + } + + /** + * Store a block. + * + * Either this method or storeItem needs to be overridden + * + * @param id + * @throws BlockBagException + */ + public void storeBlock(int id) throws BlockBagException { + storeItem(new BaseItem(id)); + } + + /** + * Store a block. + * + * Either this method or storeBlock needs to be overridden + * + * @param item + * @throws BlockBagException + */ + public void storeItem(BaseItem item) throws BlockBagException { + storeBlock(item.getType()); + } + + /** + * Checks to see if a block exists without removing it. + * + * @param id + * @return whether the block exists + */ + public boolean peekBlock(int id) { + try { + fetchBlock(id); + storeBlock(id); + return true; + } catch (BlockBagException e) { + return false; + } + } + + /** + * Flush any changes. This is called at the end. + */ + public abstract void flushChanges(); + + /** + * Adds a position to be used a source. + * + * @param pos + */ + public abstract void addSourcePosition(WorldVector pos); + + /** + * Adds a position to be used a source. + * + * @param pos + */ + public abstract void addSingleSourcePosition(WorldVector pos); +} diff --git a/src/main/java/com/sk89q/worldedit/bags/BlockBagException.java b/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagException.java similarity index 93% rename from src/main/java/com/sk89q/worldedit/bags/BlockBagException.java rename to src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagException.java index 0104737c8..c17595098 100644 --- a/src/main/java/com/sk89q/worldedit/bags/BlockBagException.java +++ b/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagException.java @@ -1,28 +1,28 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.bags; - -/** - * - * @author sk89q - */ -public class BlockBagException extends Exception { - private static final long serialVersionUID = 4672190086028430655L; -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.extent.inventory; + +/** + * + * @author sk89q + */ +public class BlockBagException extends Exception { + private static final long serialVersionUID = 4672190086028430655L; +} diff --git a/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagExtent.java b/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagExtent.java new file mode 100644 index 000000000..91fc2e1f6 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagExtent.java @@ -0,0 +1,120 @@ +/* + * 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.extent.inventory; + +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.blocks.BaseBlock; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Applies a {@link BlockBag} to operations. + */ +public class BlockBagExtent extends AbstractDelegateExtent { + + private final LocalWorld world; + private Map missingBlocks = new HashMap(); + private BlockBag blockBag; + + /** + * Create a new instance. + * + * @param extent the extent + * @param world the world + * @param blockBag the block bag + */ + public BlockBagExtent(Extent extent, LocalWorld world, @Nullable BlockBag blockBag) { + super(extent); + checkNotNull(world); + this.world = world; + this.blockBag = blockBag; + } + + /** + * Get the block bag. + * + * @return a block bag, which may be null if none is used + */ + public @Nullable BlockBag getBlockBag() { + return blockBag; + } + + /** + * Set the block bag. + * + * @param blockBag a block bag, which may be null if none is used + */ + public void setBlockBag(@Nullable BlockBag blockBag) { + this.blockBag = blockBag; + } + + /** + * Gets the list of missing blocks and clears the list for the next + * operation. + * + * @return a map of missing blocks + */ + public Map popMissing() { + Map missingBlocks = this.missingBlocks; + this.missingBlocks = new HashMap(); + return missingBlocks; + } + + @Override + public boolean setBlock(Vector position, BaseBlock block) throws WorldEditException { + if (blockBag != null) { + BaseBlock lazyBlock = getExtent().getLazyBlock(position); + int existing = lazyBlock.getType(); + final int type = block.getType(); + + if (type > 0) { + try { + blockBag.fetchPlacedBlock(type, 0); + } catch (UnplaceableBlockException e) { + return false; + } catch (BlockBagException e) { + if (!missingBlocks.containsKey(type)) { + missingBlocks.put(type, 1); + } else { + missingBlocks.put(type, missingBlocks.get(type) + 1); + } + return false; + } + } + + if (existing > 0) { + try { + blockBag.storeDroppedBlock(existing, lazyBlock.getData()); + } catch (BlockBagException ignored) { + } + } + } + + return super.setBlock(position, block); + } +} diff --git a/src/main/java/com/sk89q/worldedit/bags/OutOfBlocksException.java b/src/main/java/com/sk89q/worldedit/extent/inventory/OutOfBlocksException.java similarity index 93% rename from src/main/java/com/sk89q/worldedit/bags/OutOfBlocksException.java rename to src/main/java/com/sk89q/worldedit/extent/inventory/OutOfBlocksException.java index 4733d4920..8714cc067 100644 --- a/src/main/java/com/sk89q/worldedit/bags/OutOfBlocksException.java +++ b/src/main/java/com/sk89q/worldedit/extent/inventory/OutOfBlocksException.java @@ -1,28 +1,28 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.bags; - -/** - * - * @author sk89q - */ -public class OutOfBlocksException extends BlockBagException { - private static final long serialVersionUID = 7495899825677689509L; -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.extent.inventory; + +/** + * + * @author sk89q + */ +public class OutOfBlocksException extends BlockBagException { + private static final long serialVersionUID = 7495899825677689509L; +} diff --git a/src/main/java/com/sk89q/worldedit/bags/OutOfSpaceException.java b/src/main/java/com/sk89q/worldedit/extent/inventory/OutOfSpaceException.java similarity index 93% rename from src/main/java/com/sk89q/worldedit/bags/OutOfSpaceException.java rename to src/main/java/com/sk89q/worldedit/extent/inventory/OutOfSpaceException.java index 7dd5435fe..066aed6ac 100644 --- a/src/main/java/com/sk89q/worldedit/bags/OutOfSpaceException.java +++ b/src/main/java/com/sk89q/worldedit/extent/inventory/OutOfSpaceException.java @@ -1,48 +1,48 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.bags; - -/** - * - * @author sk89q - */ -public class OutOfSpaceException extends BlockBagException { - private static final long serialVersionUID = -2962840237632916821L; - - /** - * Stores the block ID. - */ - private int id; - - /** - * Construct the object. - * @param id - */ - public OutOfSpaceException(int id) { - this.id = id; - } - - /** - * @return the id - */ - public int getID() { - return id; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.extent.inventory; + +/** + * + * @author sk89q + */ +public class OutOfSpaceException extends BlockBagException { + private static final long serialVersionUID = -2962840237632916821L; + + /** + * Stores the block ID. + */ + private int id; + + /** + * Construct the object. + * @param id + */ + public OutOfSpaceException(int id) { + this.id = id; + } + + /** + * @return the id + */ + public int getID() { + return id; + } +} diff --git a/src/main/java/com/sk89q/worldedit/bags/UnplaceableBlockException.java b/src/main/java/com/sk89q/worldedit/extent/inventory/UnplaceableBlockException.java similarity index 93% rename from src/main/java/com/sk89q/worldedit/bags/UnplaceableBlockException.java rename to src/main/java/com/sk89q/worldedit/extent/inventory/UnplaceableBlockException.java index 28c4014b7..459b501a1 100644 --- a/src/main/java/com/sk89q/worldedit/bags/UnplaceableBlockException.java +++ b/src/main/java/com/sk89q/worldedit/extent/inventory/UnplaceableBlockException.java @@ -1,29 +1,29 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.bags; - -/** - * - * @author sk89q - */ -public class UnplaceableBlockException extends BlockBagException { - private static final long serialVersionUID = 7227883966999843526L; - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.extent.inventory; + +/** + * + * @author sk89q + */ +public class UnplaceableBlockException extends BlockBagException { + private static final long serialVersionUID = 7227883966999843526L; + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/logging/AbstractLoggingExtent.java b/src/main/java/com/sk89q/worldedit/extent/logging/AbstractLoggingExtent.java new file mode 100644 index 000000000..5d9ad031b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/logging/AbstractLoggingExtent.java @@ -0,0 +1,57 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.extent.logging; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; + +/** + * An abstract class to implement block loggers and so on with. + */ +public abstract class AbstractLoggingExtent extends AbstractDelegateExtent { + + /** + * Create a new instance. + * + * @param extent the extent + */ + protected AbstractLoggingExtent(Extent extent) { + super(extent); + } + + /** + * Called when a block is being changed. + * + * @param position the position + * @param newBlock the new block to replace the old one + */ + protected void onBlockChange(Vector position, BaseBlock newBlock) { + } + + @Override + public final boolean setBlock(Vector position, BaseBlock block) throws WorldEditException { + onBlockChange(position, block); + return super.setBlock(position, block); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java b/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java new file mode 100644 index 000000000..dbd786be8 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java @@ -0,0 +1,218 @@ +/* + * 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.extent.reorder; + +import com.google.common.collect.Iterators; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.PlayerDirection; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockID; +import com.sk89q.worldedit.blocks.BlockType; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.operation.BlockMapEntryPlacer; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.OperationQueue; +import com.sk89q.worldedit.function.operation.RunContext; +import com.sk89q.worldedit.util.collection.TupleArrayList; + +import java.util.*; + +/** + * Re-orders blocks into several stages. + */ +public class MultiStageReorder extends AbstractDelegateExtent implements ReorderingExtent { + + private TupleArrayList stage1 = new TupleArrayList(); + private TupleArrayList stage2 = new TupleArrayList(); + private TupleArrayList stage3 = new TupleArrayList(); + private boolean enabled; + + /** + * Create a new instance. + * + * @param extent the extent + * @param enabled true to enable + */ + public MultiStageReorder(Extent extent, boolean enabled) { + super(extent); + this.enabled = enabled; + } + + /** + * Create a new instance when the re-ordering is enabled. + * + * @param extent the extent + */ + public MultiStageReorder(Extent extent) { + this(extent, true); + } + + /** + * Return whether re-ordering is enabled. + * + * @return true if re-ordering is enabled + */ + public boolean isEnabled() { + return enabled; + } + + /** + * Set whether re-ordering is enabled. + * + * @param enabled true if re-ordering is enabled + */ + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + @Override + public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException { + BaseBlock lazyBlock = getLazyBlock(location); + + if (!enabled) { + return super.setBlock(location, block); + } + + if (BlockType.shouldPlaceLast(block.getType())) { + // Place torches, etc. last + stage2.put(location.toBlockVector(), block); + return !(lazyBlock.getType() == block.getType() && lazyBlock.getData() == block.getData()); + } else if (BlockType.shouldPlaceFinal(block.getType())) { + // Place signs, reed, etc even later + stage3.put(location.toBlockVector(), block); + return !(lazyBlock.getType() == block.getType() && lazyBlock.getData() == block.getData()); + } else if (BlockType.shouldPlaceLast(lazyBlock.getType())) { + // Destroy torches, etc. first + super.setBlock(location, new BaseBlock(BlockID.AIR)); + return super.setBlock(location, block); + } else { + stage1.put(location.toBlockVector(), block); + return !(lazyBlock.getType() == block.getType() && lazyBlock.getData() == block.getData()); + } + } + + @Override + public Operation commitBefore() { + return new OperationQueue( + new BlockMapEntryPlacer( + getExtent(), + Iterators.concat(stage1.iterator(), stage2.iterator())), + new Stage3Committer()); + } + + private class Stage3Committer implements Operation { + + @Override + public Operation resume(RunContext run) throws WorldEditException { + Extent extent = getExtent(); + + final Set blocks = new HashSet(); + final Map blockTypes = new HashMap(); + for (Map.Entry entry : stage3) { + final BlockVector pt = entry.getKey(); + blocks.add(pt); + blockTypes.put(pt, entry.getValue()); + } + + while (!blocks.isEmpty()) { + BlockVector current = blocks.iterator().next(); + if (!blocks.contains(current)) { + continue; + } + + final Deque walked = new LinkedList(); + + while (true) { + walked.addFirst(current); + + assert (blockTypes.containsKey(current)); + + final BaseBlock baseBlock = blockTypes.get(current); + + final int type = baseBlock.getType(); + final int data = baseBlock.getData(); + + switch (type) { + case BlockID.WOODEN_DOOR: + case BlockID.IRON_DOOR: + if ((data & 0x8) == 0) { + // Deal with lower door halves being attached to the floor AND the upper half + BlockVector upperBlock = current.add(0, 1, 0).toBlockVector(); + if (blocks.contains(upperBlock) && !walked.contains(upperBlock)) { + walked.addFirst(upperBlock); + } + } + break; + + case BlockID.MINECART_TRACKS: + case BlockID.POWERED_RAIL: + case BlockID.DETECTOR_RAIL: + case BlockID.ACTIVATOR_RAIL: + // Here, rails are hardcoded to be attached to the block below them. + // They're also attached to the block they're ascending towards via BlockType.getAttachment. + BlockVector lowerBlock = current.add(0, -1, 0).toBlockVector(); + if (blocks.contains(lowerBlock) && !walked.contains(lowerBlock)) { + walked.addFirst(lowerBlock); + } + break; + } + + final PlayerDirection attachment = BlockType.getAttachment(type, data); + if (attachment == null) { + // Block is not attached to anything => we can place it + break; + } + + current = current.add(attachment.vector()).toBlockVector(); + + if (!blocks.contains(current)) { + // We ran outside the remaing set => assume we can place blocks on this + break; + } + + if (walked.contains(current)) { + // Cycle detected => This will most likely go wrong, but there's nothing we can do about it. + break; + } + } + + for (BlockVector pt : walked) { + extent.setBlock(pt, blockTypes.get(pt)); + blocks.remove(pt); + } + } + + stage1.clear(); + stage2.clear(); + stage3.clear(); + + return null; + } + + @Override + public void cancel() { + } + + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/reorder/ReorderingExtent.java b/src/main/java/com/sk89q/worldedit/extent/reorder/ReorderingExtent.java new file mode 100644 index 000000000..bb605cfed --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/reorder/ReorderingExtent.java @@ -0,0 +1,34 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.extent.reorder; + +import com.sk89q.worldedit.extent.Extent; + +/** + * An interface for {@link Extent}s that are meant to reorder changes so + * that they are more successful. + *

+ * For example, torches in Minecraft need to be placed on a block. A smart + * reordering implementation might place the torch after the block has + * been placed. + */ +public interface ReorderingExtent extends Extent { + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/validation/BlockChangeLimiter.java b/src/main/java/com/sk89q/worldedit/extent/validation/BlockChangeLimiter.java new file mode 100644 index 000000000..817b3e00b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/validation/BlockChangeLimiter.java @@ -0,0 +1,89 @@ +/* + * 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.extent.validation; + +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Limits the number of blocks that can be changed before a + * {@link MaxChangedBlocksException} is thrown. + */ +public class BlockChangeLimiter extends AbstractDelegateExtent { + + private int limit; + private int count = 0; + + /** + * Create a new instance. + * + * @param extent the extent + * @param limit the limit (>= 0) or -1 for no limit + */ + public BlockChangeLimiter(Extent extent, int limit) { + super(extent); + setLimit(limit); + } + + /** + * Get the limit. + * + * @return the limit (>= 0) or -1 for no limit + */ + public int getLimit() { + return limit; + } + + /** + * Set the limit. + * + * @param limit the limit (>= 0) or -1 for no limit + */ + public void setLimit(int limit) { + checkArgument(limit >= -1, "limit >= -1 required"); + this.limit = limit; + } + + /** + * Get the number of blocks that have been counted so far. + * + * @return the number of blocks + */ + public int getCount() { + return count; + } + + @Override + public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException { + if (limit >= 0) { + if (count >= limit) { + throw new MaxChangedBlocksException(limit); + } + count++; + } + return super.setBlock(location, block); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/validation/DataValidatorExtent.java b/src/main/java/com/sk89q/worldedit/extent/validation/DataValidatorExtent.java new file mode 100644 index 000000000..91e9b9daa --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/validation/DataValidatorExtent.java @@ -0,0 +1,69 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.extent.validation; + +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Validates set data to prevent creating invalid blocks and such. + */ +public class DataValidatorExtent extends AbstractDelegateExtent { + + private final LocalWorld world; + + /** + * Create a new instance. + * + * @param extent the extent + * @param world the world + */ + public DataValidatorExtent(Extent extent, LocalWorld world) { + super(extent); + checkNotNull(world); + this.world = world; + } + + @Override + public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException { + final int y = location.getBlockY(); + final int type = block.getType(); + if (y < 0 || y > world.getMaxY()) { + return false; + } + + // No invalid blocks + if (!world.isValidBlockType(type)) { + return false; + } + + if (type == 0) { + block.setData(0); + } + + return super.setBlock(location, block); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/world/BlockQuirkExtent.java b/src/main/java/com/sk89q/worldedit/extent/world/BlockQuirkExtent.java new file mode 100644 index 000000000..009115128 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/world/BlockQuirkExtent.java @@ -0,0 +1,67 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.extent.world; + +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockID; +import com.sk89q.worldedit.blocks.BlockType; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Handles various quirks when setting blocks, such as ice turning + * into water or containers dropping their contents. + */ +public class BlockQuirkExtent extends AbstractDelegateExtent { + + private final LocalWorld world; + + /** + * Create a new instance. + * + * @param extent the extent + * @param world the world + */ + public BlockQuirkExtent(Extent extent, LocalWorld world) { + super(extent); + checkNotNull(world); + this.world = world; + } + + @Override + public boolean setBlock(Vector position, BaseBlock block) throws WorldEditException { + BaseBlock lazyBlock = getExtent().getLazyBlock(position); + int existing = lazyBlock.getType(); + + if (BlockType.isContainerBlock(existing)) { + world.clearContainerBlockContents(position); // Clear the container block so that it doesn't drop items + } else if (existing == BlockID.ICE) { + world.setBlock(position, new BaseBlock(BlockID.AIR)); // Ice turns until water so this has to be done first + } + + return super.setBlock(position, block); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/extent/world/ChunkLoadingExtent.java b/src/main/java/com/sk89q/worldedit/extent/world/ChunkLoadingExtent.java new file mode 100644 index 000000000..9902dec70 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/world/ChunkLoadingExtent.java @@ -0,0 +1,68 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.extent.world; + +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Automatically loads chunks when blocks are accessed. + */ +public class ChunkLoadingExtent extends AbstractDelegateExtent { + + private final LocalWorld world; + private boolean enabled; + + /** + * Create a new instance. + * + * @param extent the extent + * @param world the world + * @param enabled true to enable + */ + public ChunkLoadingExtent(Extent extent, LocalWorld world, boolean enabled) { + super(extent); + checkNotNull(world); + this.enabled = enabled; + this.world = world; + } + + /** + * Create a new instance with chunk loading enabled. + * + * @param extent the extent + * @param world the world + */ + public ChunkLoadingExtent(Extent extent, LocalWorld world) { + this(extent, world, true); + } + + @Override + public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException { + world.checkLoadedChunk(location); + return super.setBlock(location, block); + } +} diff --git a/src/main/java/com/sk89q/worldedit/extent/world/FastModeExtent.java b/src/main/java/com/sk89q/worldedit/extent/world/FastModeExtent.java new file mode 100644 index 000000000..194f5a85d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/extent/world/FastModeExtent.java @@ -0,0 +1,112 @@ +/* + * 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.extent.world; + +import com.sk89q.worldedit.BlockVector2D; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.RunContext; + +import java.util.HashSet; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Implements "fast mode" which may skip physics, lighting, etc. + */ +public class FastModeExtent extends AbstractDelegateExtent { + + private final LocalWorld world; + private final Set dirtyChunks = new HashSet(); + private boolean enabled = true; + + /** + * Create a new instance with fast mode enabled. + * + * @param world the world + */ + public FastModeExtent(LocalWorld world) { + this(world, true); + } + + /** + * Create a new instance. + * + * @param world the world + * @param enabled true to enable fast mode + */ + public FastModeExtent(LocalWorld world, boolean enabled) { + super(world); + checkNotNull(world); + this.world = world; + this.enabled = enabled; + } + + /** + * Return whether fast mode is enabled. + * + * @return true if fast mode is enabled + */ + public boolean isEnabled() { + return enabled; + } + + /** + * Set fast mode enable status. + * + * @param enabled true to enable fast mode + */ + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + @Override + public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException { + if (enabled) { + dirtyChunks.add(new BlockVector2D(location.getBlockX() >> 4, location.getBlockZ() >> 4)); + return world.setBlock(location, block, false); + } else { + return world.setBlock(location, block, true); + } + } + + @Override + protected Operation commitBefore() { + return new Operation() { + @Override + public Operation resume(RunContext run) throws WorldEditException { + if (dirtyChunks.size() > 0) { + world.fixAfterFastMode(dirtyChunks); + } + return null; + } + + @Override + public void cancel() { + } + }; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/foundation/Block.java b/src/main/java/com/sk89q/worldedit/foundation/Block.java deleted file mode 100644 index 464ad2173..000000000 --- a/src/main/java/com/sk89q/worldedit/foundation/Block.java +++ /dev/null @@ -1,230 +0,0 @@ -// $Id$ -/* - * This file is a part of WorldEdit. - * Copyright (c) sk89q - * Copyright (c) the 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 - * (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 - * 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 . -*/ - -package com.sk89q.worldedit.foundation; - -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.blocks.TileEntityBlock; -import com.sk89q.worldedit.data.DataException; - -/** - * Represents a mutable copy of a block that is not tied to any 'real' block in a world. - * A single instance of this can be set to multiple locations and each location would - * have a copy of this instance's data. - *

- * Implementations can and should extend this class to allow native implementations - * of NBT data handling, primarily for performance reasons. Subclasses can only convert - * from and to WorldEdit-native NBT structures when absolutely necessary (a.k.a. when - * {@link #getNbtData()} and {@link #setNbtData(CompoundTag)} are called). When - * overriding the NBT methods, {@link #getNbtId()} should be overridden too, otherwise - * the default implementation will invoke {@link #getNbtData()}, a potentially costly - * operation when it is not needed. Implementations may want to cache converted NBT data - * structures if possible. - *

- * Currently, {@link BaseBlock} is used throughout WorldEdit and implementations, but - * eventually an API-breaking transition will occur to switch to this object instead. - * As-is, the definition of this class is complete, but may need changes in MC 1.4 - * because data values may be eradicated. - */ -public class Block implements TileEntityBlock { - - /** - * Indicates the highest possible block ID (inclusive) that can be used. This value - * is subject to change depending on the implementation, but internally this class - * only supports a range of 4096 IDs (for space reasons), which coincides with the - * number of possible IDs that official Minecraft supports as of version 1.3. - */ - public static final int MAX_ID = 4095; - - /** - * Indicates the maximum data value (inclusive) that can be used. Minecraft 1.4 may - * abolish usage of data values and this value may be removed in the future. - */ - public static final int MAX_DATA = 15; - - // Instances of this class should be _as small as possible_ because there will - // be millions of instances of this object. - - private short id; - private short data; - private CompoundTag nbtData; - - /** - * Construct a block with the given ID and a data value of 0. - * - * @param id ID value - * @see #setId(int) - */ - public Block(int id) { - setId(id); - setData(0); - } - - /** - * Construct a block with the given ID and data value. - * - * @param id ID value - * @param data data value - * @see #setId(int) - * @see #setData(int) - */ - public Block(int id, int data) { - setId(id); - setData(data); - } - - /** - * Construct a block with the given ID, data value, and NBT data structure. - * - * @param id ID value - * @param data data value - * @param nbtData NBT data - * @throws DataException if possibly the data is invalid - * @see #setId(int) - * @see #setData(int) - * @see #setNbtData(CompoundTag) - */ - public Block(int id, int data, CompoundTag nbtData) throws DataException { - setId(id); - setData(data); - setNbtData(nbtData); - } - - /** - * Get the ID of the block. - * - * @return ID (between 0 and {@link #MAX_ID}) - */ - public int getId() { - return id; - } - - /** - * Set the block ID. - * - * @param id block id (between 0 and {@link #MAX_ID}). - */ - public void setId(int id) { - if (id > MAX_ID) { - throw new IllegalArgumentException("Can't have a block ID above " - + MAX_ID + " (" + id + " given)"); - } - - if (id < 0) { - throw new IllegalArgumentException("Can't have a block ID below 0"); - } - - this.id = (short) id; - } - - /** - * Get the block's data value. - * - * @return data value (0-15) - */ - public int getData() { - return data; - } - - /** - * Set the block's data value. - * - * @param data block data value (between 0 and {@link #MAX_DATA}). - */ - public void setData(int data) { - if (data > MAX_DATA) { - throw new IllegalArgumentException( - "Can't have a block data value above " + MAX_DATA + " (" - + data + " given)"); - } - - if (data < -1) { - throw new IllegalArgumentException("Can't have a block data value below -1"); - } - - this.data = (short) data; - } - - /** - * Set both the block's ID and data value. - * - * @param id ID value - * @param data data value - * @see #setId(int) - * @see #setData(int) - */ - public void setIdAndData(int id, int data) { - setId(id); - setData(data); - } - - /** - * Returns whether the data value is -1, indicating that this block is to be - * used as a wildcard matching block. - * - * @return true if the data value is -1 - */ - public boolean hasWildcardData() { - return getData() == -1; - } - - @Override - public boolean hasNbtData() { - return getNbtData() != null; - } - - @Override - public String getNbtId() { - CompoundTag nbtData = getNbtData(); - if (nbtData == null) { - return ""; - } - Tag idTag = nbtData.getValue().get("id"); - if (idTag != null && idTag instanceof StringTag) { - return ((StringTag) idTag).getValue(); - } else { - return ""; - } - } - - @Override - public CompoundTag getNbtData() { - return nbtData; - } - - @Override - public void setNbtData(CompoundTag nbtData) throws DataException { - this.nbtData = nbtData; - } - - @Override - public int hashCode() { - int ret = getId() << 3; - if (getData() != (byte) -1) ret |= getData(); - return ret; - } - - @Override - public String toString() { - return "Block{ID:" + getId() + ", Data: " + getData() + "}"; - } - -} diff --git a/src/main/java/com/sk89q/worldedit/function/CombinedRegionFunction.java b/src/main/java/com/sk89q/worldedit/function/CombinedRegionFunction.java new file mode 100644 index 000000000..20e819454 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/CombinedRegionFunction.java @@ -0,0 +1,91 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; + +import java.util.*; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Executes several region functions in order. + */ +public class CombinedRegionFunction implements RegionFunction { + + private final List functions = new ArrayList(); + + /** + * Create a combined region function. + */ + public CombinedRegionFunction() { + } + + /** + * Create a combined region function. + * + * @param functions a list of functions to match + */ + public CombinedRegionFunction(Collection functions) { + checkNotNull(functions); + this.functions.addAll(functions); + } + + /** + * Create a combined region function. + * + * @param function an array of functions to match + */ + public CombinedRegionFunction(RegionFunction... function) { + this(Arrays.asList(checkNotNull(function))); + } + + /** + * Add the given functions to the list of functions to call. + * + * @param functions a list of functions + */ + public void add(Collection functions) { + checkNotNull(functions); + this.functions.addAll(functions); + } + + /** + * Add the given functions to the list of functions to call. + * + * @param function an array of functions + */ + public void add(RegionFunction... function) { + add(Arrays.asList(checkNotNull(function))); + } + + @Override + public boolean apply(Vector position) throws WorldEditException { + boolean ret = false; + for (RegionFunction function : functions) { + if (function.apply(position)) { + ret = true; + } + } + return ret; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/operation/FlatRegionFunction.java b/src/main/java/com/sk89q/worldedit/function/FlatRegionFunction.java similarity index 73% rename from src/main/java/com/sk89q/worldedit/operation/FlatRegionFunction.java rename to src/main/java/com/sk89q/worldedit/function/FlatRegionFunction.java index 88f1039fa..03cb99b5d 100644 --- a/src/main/java/com/sk89q/worldedit/operation/FlatRegionFunction.java +++ b/src/main/java/com/sk89q/worldedit/function/FlatRegionFunction.java @@ -17,23 +17,25 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.operation; +package com.sk89q.worldedit.function; import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.regions.FlatRegion; /** - * Performs a function on points in a flat region. + * Performs a function on the columns in a {@link FlatRegion}, or also + * known as vectors with only X and Z components (where Y is height). */ public interface FlatRegionFunction { /** - * Apply the function to the given point. + * Apply the function to the given position. * - * @param pt the point + * @param position the position * @return true if something was changed * @throws WorldEditException thrown on an error */ - public boolean apply(Vector2D pt) throws WorldEditException; + public boolean apply(Vector2D position) throws WorldEditException; } diff --git a/src/main/java/com/sk89q/worldedit/function/FlatRegionMaskingFilter.java b/src/main/java/com/sk89q/worldedit/function/FlatRegionMaskingFilter.java new file mode 100644 index 000000000..df28989a5 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/FlatRegionMaskingFilter.java @@ -0,0 +1,57 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function; + +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.mask.Mask2D; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Passes calls to {@link #apply(com.sk89q.worldedit.Vector2D)} to the + * delegate {@link com.sk89q.worldedit.function.FlatRegionFunction} if they + * match the given mask. + */ +public class FlatRegionMaskingFilter implements FlatRegionFunction { + + private final FlatRegionFunction function; + private Mask2D mask; + + /** + * Create a new masking filter. + * + * @param mask the mask + * @param function the delegate function to call + */ + public FlatRegionMaskingFilter(Mask2D mask, FlatRegionFunction function) { + checkNotNull(function); + checkNotNull(mask); + + this.mask = mask; + this.function = function; + } + + @Override + public boolean apply(Vector2D position) throws WorldEditException { + return mask.test(position) && function.apply(position); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/GroundFunction.java b/src/main/java/com/sk89q/worldedit/function/GroundFunction.java new file mode 100644 index 000000000..e17861391 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/GroundFunction.java @@ -0,0 +1,94 @@ +/* + * 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.function; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.mask.Mask; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Applies a {@link RegionFunction} to the first ground block. + */ +public class GroundFunction implements LayerFunction { + + private Mask mask; + private final RegionFunction function; + private int affected; + + /** + * Create a new ground function. + * + * @param mask a mask + * @param function the function to apply + */ + public GroundFunction(Mask mask, RegionFunction function) { + checkNotNull(mask); + checkNotNull(function); + this.mask = mask; + this.function = function; + } + + /** + * Get the mask that determines what the ground consists of. + * + * @return a mask + */ + public Mask getMask() { + return mask; + } + + /** + * Set the mask that determines what the ground consists of. + * + * @param mask a mask + */ + public void setMask(Mask mask) { + checkNotNull(mask); + this.mask = mask; + } + + /** + * Get the number of affected objects. + * + * @return the number of affected + */ + public int getAffected() { + return affected; + } + + @Override + public boolean isGround(Vector position) { + return mask.test(position); + } + + @Override + public boolean apply(Vector position, int depth) throws WorldEditException { + if (depth == 0) { + if (function.apply(position)) { + affected++; + } + } + + return false; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/LayerFunction.java b/src/main/java/com/sk89q/worldedit/function/LayerFunction.java new file mode 100644 index 000000000..dcc26db2e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/LayerFunction.java @@ -0,0 +1,52 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.visitor.LayerVisitor; + +/** + * A function that takes a position and a depth. + */ +public interface LayerFunction { + + /** + * Returns whether the given block should be "passed through" when + * conducting the ground search. + * + * @param position return whether the given block is the ground + * @return true if the search should stop + */ + boolean isGround(Vector position); + + /** + * Apply the function to the given position. + *

+ * The depth would be the number of blocks from the surface if + * a {@link LayerVisitor} was used. + * + * @param position the position + * @param depth the depth as a number starting from 0 + * @return true whether this method should be called for further layers + * @throws WorldEditException thrown on an error + */ + boolean apply(Vector position, int depth) throws WorldEditException; +} diff --git a/src/main/java/com/sk89q/worldedit/operation/RegionFunction.java b/src/main/java/com/sk89q/worldedit/function/RegionFunction.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/operation/RegionFunction.java rename to src/main/java/com/sk89q/worldedit/function/RegionFunction.java index 8707d7c4f..1f13a2cad 100644 --- a/src/main/java/com/sk89q/worldedit/operation/RegionFunction.java +++ b/src/main/java/com/sk89q/worldedit/function/RegionFunction.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.operation; +package com.sk89q.worldedit.function; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; diff --git a/src/main/java/com/sk89q/worldedit/function/RegionMaskingFilter.java b/src/main/java/com/sk89q/worldedit/function/RegionMaskingFilter.java new file mode 100644 index 000000000..cd0ac45b7 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/RegionMaskingFilter.java @@ -0,0 +1,56 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.mask.Mask; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Passes calls to {@link #apply(com.sk89q.worldedit.Vector)} to the + * delegate {@link com.sk89q.worldedit.function.RegionFunction} if they + * match the given mask. + */ +public class RegionMaskingFilter implements RegionFunction { + + private final RegionFunction function; + private Mask mask; + + /** + * Create a new masking filter. + * + * @param mask the mask + * @param function the function + */ + public RegionMaskingFilter(Mask mask, RegionFunction function) { + checkNotNull(function); + checkNotNull(mask); + this.mask = mask; + this.function = function; + } + + @Override + public boolean apply(Vector position) throws WorldEditException { + return mask.test(position) && function.apply(position); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/block/BlockReplace.java b/src/main/java/com/sk89q/worldedit/function/block/BlockReplace.java new file mode 100644 index 000000000..463df488f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/block/BlockReplace.java @@ -0,0 +1,56 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function.block; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.pattern.Pattern; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Replaces blocks with a given pattern. + */ +public class BlockReplace implements RegionFunction { + + private final Extent extent; + private Pattern pattern; + + /** + * Create a new instance. + * + * @param extent an extent + * @param pattern a pattern + */ + public BlockReplace(Extent extent, Pattern pattern) { + checkNotNull(extent); + checkNotNull(pattern); + this.extent = extent; + this.pattern = pattern; + } + + @Override + public boolean apply(Vector position) throws WorldEditException { + return extent.setBlock(position, pattern.apply(position)); + } + +} \ No newline at end of file diff --git a/src/main/java/com/sk89q/worldedit/function/block/Counter.java b/src/main/java/com/sk89q/worldedit/function/block/Counter.java new file mode 100644 index 000000000..4ea2c4814 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/block/Counter.java @@ -0,0 +1,48 @@ +/* + * 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.function.block; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.RegionFunction; + +/** + * Keeps a count of the number of times that {@link #apply(Vector)} is called. + */ + public class Counter implements RegionFunction { + + private int count; + + /** + * Returns the number of blocks that have been counted. + * + * @return the number of blocks + */ + public int getCount() { + return count; + } + + @Override + public boolean apply(Vector position) throws WorldEditException { + count++; + return false; + } + +} \ No newline at end of file diff --git a/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java b/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java new file mode 100644 index 000000000..4632b387c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java @@ -0,0 +1,70 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function.block; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.math.transform.Transform; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Copies blocks from one extent to another. + */ +public class ExtentBlockCopy implements RegionFunction { + + private final Extent source; + private final Extent destination; + private final Vector from; + private final Vector to; + private final Transform transform; + + /** + * Make a new copy. + * + * @param source the source extent + * @param from the source offset + * @param destination the destination extent + * @param to the destination offset + * @param transform a transform to apply to positions (after source offset, before destination offset) + */ + public ExtentBlockCopy(Extent source, Vector from, Extent destination, Vector to, Transform transform) { + checkNotNull(source); + checkNotNull(from); + checkNotNull(destination); + checkNotNull(to); + checkNotNull(transform); + this.source = source; + this.from = from; + this.destination = destination; + this.to = to; + this.transform = transform; + } + + @Override + public boolean apply(Vector position) throws WorldEditException { + BaseBlock block = source.getBlock(position); + return destination.setBlock(transform.apply(position.subtract(from)).add(to), block); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/block/Naturalizer.java b/src/main/java/com/sk89q/worldedit/function/block/Naturalizer.java new file mode 100644 index 000000000..b2143319b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/block/Naturalizer.java @@ -0,0 +1,91 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function.block; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockID; +import com.sk89q.worldedit.function.LayerFunction; +import com.sk89q.worldedit.masks.BlockMask; +import com.sk89q.worldedit.masks.Mask; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Makes a layer of grass on top, three layers of dirt below, and smooth stone + * only below that for all layers that originally consist of grass, dirt, + * or smooth stone. + */ +public class Naturalizer implements LayerFunction { + + private final EditSession editSession; + private final BaseBlock grass = new BaseBlock(BlockID.GRASS); + private final BaseBlock dirt = new BaseBlock(BlockID.DIRT); + private final BaseBlock stone = new BaseBlock(BlockID.STONE); + private final Mask mask = new BlockMask(grass, dirt, stone); + private int affected = 0; + + /** + * Make a new naturalizer. + * + * @param editSession an edit session + */ + public Naturalizer(EditSession editSession) { + checkNotNull(editSession); + this.editSession = editSession; + } + + /** + * Get the number of affected objects. + * + * @return the number of affected + */ + public int getAffected() { + return affected; + } + + @Override + public boolean isGround(Vector position) { + return mask.matches(editSession, position); + } + + @Override + public boolean apply(Vector position, int depth) throws WorldEditException { + if (mask.matches(editSession, position)) { + affected++; + switch (depth) { + case 0: + editSession.setBlock(position, grass); + break; + case 1: + case 2: + case 3: + editSession.setBlock(position, dirt); + break; + default: + editSession.setBlock(position, stone); + } + } + + return true; + } +} diff --git a/src/main/java/com/sk89q/worldedit/generator/FloraGenerator.java b/src/main/java/com/sk89q/worldedit/function/generator/FloraGenerator.java similarity index 76% rename from src/main/java/com/sk89q/worldedit/generator/FloraGenerator.java rename to src/main/java/com/sk89q/worldedit/function/generator/FloraGenerator.java index 7ddb06678..9eff8bc63 100644 --- a/src/main/java/com/sk89q/worldedit/generator/FloraGenerator.java +++ b/src/main/java/com/sk89q/worldedit/function/generator/FloraGenerator.java @@ -17,20 +17,17 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.generator; +package com.sk89q.worldedit.function.generator; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BlockID; -import com.sk89q.worldedit.operation.RegionFunction; -import com.sk89q.worldedit.patterns.BlockChance; -import com.sk89q.worldedit.patterns.Pattern; -import com.sk89q.worldedit.patterns.RandomFillPattern; - -import java.util.ArrayList; -import java.util.List; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.pattern.BlockPattern; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.function.pattern.RandomPattern; /** * Generates flora (which may include tall grass, flowers, etc.). @@ -85,11 +82,11 @@ public class FloraGenerator implements RegionFunction { * @return a pattern that places flora */ public static Pattern getDesertPattern() { - List chance = new ArrayList(); - chance.add(new BlockChance(new BaseBlock(BlockID.DEAD_BUSH), 30)); - chance.add(new BlockChance(new BaseBlock(BlockID.CACTUS), 20)); - chance.add(new BlockChance(new BaseBlock(BlockID.AIR), 300)); - return new RandomFillPattern(chance); + RandomPattern pattern = new RandomPattern(); + pattern.add(new BlockPattern(new BaseBlock(BlockID.DEAD_BUSH)), 30); + pattern.add(new BlockPattern(new BaseBlock(BlockID.CACTUS)), 20); + pattern.add(new BlockPattern(new BaseBlock(BlockID.AIR)), 300); + return pattern; } /** @@ -98,11 +95,11 @@ public class FloraGenerator implements RegionFunction { * @return a pattern that places flora */ public static Pattern getTemperatePattern() { - List chance = new ArrayList(); - chance.add(new BlockChance(new BaseBlock(BlockID.LONG_GRASS, 1), 300)); - chance.add(new BlockChance(new BaseBlock(BlockID.RED_FLOWER), 5)); - chance.add(new BlockChance(new BaseBlock(BlockID.YELLOW_FLOWER), 5)); - return new RandomFillPattern(chance); + RandomPattern pattern = new RandomPattern(); + pattern.add(new BlockPattern(new BaseBlock(BlockID.LONG_GRASS, 1)), 300); + pattern.add(new BlockPattern(new BaseBlock(BlockID.RED_FLOWER)), 5); + pattern.add(new BlockPattern(new BaseBlock(BlockID.YELLOW_FLOWER)), 5); + return pattern; } @Override @@ -110,10 +107,10 @@ public class FloraGenerator implements RegionFunction { BaseBlock block = editSession.getBlock(position); if (block.getType() == BlockID.GRASS) { - editSession.setBlock(position.add(0, 1, 0), temperatePattern.next(position)); + editSession.setBlock(position.add(0, 1, 0), temperatePattern.apply(position)); return true; } else if (block.getType() == BlockID.SAND) { - editSession.setBlock(position.add(0, 1, 0), desertPattern.next(position)); + editSession.setBlock(position.add(0, 1, 0), desertPattern.apply(position)); return true; } diff --git a/src/main/java/com/sk89q/worldedit/generator/ForestGenerator.java b/src/main/java/com/sk89q/worldedit/function/generator/ForestGenerator.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/generator/ForestGenerator.java rename to src/main/java/com/sk89q/worldedit/function/generator/ForestGenerator.java index 74b41d581..42598244d 100644 --- a/src/main/java/com/sk89q/worldedit/generator/ForestGenerator.java +++ b/src/main/java/com/sk89q/worldedit/function/generator/ForestGenerator.java @@ -17,14 +17,14 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.generator; +package com.sk89q.worldedit.function.generator; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BlockID; -import com.sk89q.worldedit.operation.RegionFunction; +import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.util.TreeGenerator; /** diff --git a/src/main/java/com/sk89q/worldedit/generator/GardenPatchGenerator.java b/src/main/java/com/sk89q/worldedit/function/generator/GardenPatchGenerator.java similarity index 89% rename from src/main/java/com/sk89q/worldedit/generator/GardenPatchGenerator.java rename to src/main/java/com/sk89q/worldedit/function/generator/GardenPatchGenerator.java index 873495ceb..4447da19c 100644 --- a/src/main/java/com/sk89q/worldedit/generator/GardenPatchGenerator.java +++ b/src/main/java/com/sk89q/worldedit/function/generator/GardenPatchGenerator.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.generator; +package com.sk89q.worldedit.function.generator; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; @@ -25,16 +25,16 @@ import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BlockID; -import com.sk89q.worldedit.operation.RegionFunction; -import com.sk89q.worldedit.patterns.BlockChance; -import com.sk89q.worldedit.patterns.Pattern; -import com.sk89q.worldedit.patterns.RandomFillPattern; -import com.sk89q.worldedit.patterns.SingleBlockPattern; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.pattern.BlockPattern; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.function.pattern.RandomPattern; -import java.util.ArrayList; -import java.util.List; import java.util.Random; +/** + * Generates patches of fruit (i.e. pumpkin patches). + */ public class GardenPatchGenerator implements RegionFunction { private final Random random = new Random(); @@ -115,7 +115,7 @@ public class GardenPatchGenerator implements RegionFunction { editSession.setBlockIfAir(pos.add(1, h, -1), log); affected++; } - editSession.setBlockIfAir(p = pos.add(0, 0, -1), plant.next(p)); + editSession.setBlockIfAir(p = pos.add(0, 0, -1), plant.apply(p)); affected++; break; @@ -127,7 +127,7 @@ public class GardenPatchGenerator implements RegionFunction { editSession.setBlockIfAir(pos.add(1, h, 0), log); affected++; } - editSession.setBlockIfAir(p = pos.add(1, 0, 1), plant.next(p)); + editSession.setBlockIfAir(p = pos.add(1, 0, 1), plant.apply(p)); affected++; break; @@ -139,7 +139,7 @@ public class GardenPatchGenerator implements RegionFunction { editSession.setBlockIfAir(pos.add(-1, h, 0), log); affected++; } - editSession.setBlockIfAir(p = pos.add(-1, 0, 1), plant.next(p)); + editSession.setBlockIfAir(p = pos.add(-1, 0, 1), plant.apply(p)); affected++; break; @@ -151,7 +151,7 @@ public class GardenPatchGenerator implements RegionFunction { editSession.setBlockIfAir(pos.add(-1, h, -1), log); affected++; } - editSession.setBlockIfAir(p = pos.add(-1, 0, -1), plant.next(p)); + editSession.setBlockIfAir(p = pos.add(-1, 0, -1), plant.apply(p)); affected++; break; } @@ -185,11 +185,11 @@ public class GardenPatchGenerator implements RegionFunction { * @return a pumpkin pattern */ public static Pattern getPumpkinPattern() { - List chance = new ArrayList(); + RandomPattern pattern = new RandomPattern(); for (int i = 0; i < 4; i++) { - chance.add(new BlockChance(new BaseBlock(BlockID.PUMPKIN, i), 100)); + pattern.add(new BlockPattern(new BaseBlock(BlockID.PUMPKIN, i)), 100); } - return new RandomFillPattern(chance); + return pattern; } /** @@ -198,6 +198,6 @@ public class GardenPatchGenerator implements RegionFunction { * @return a melon pattern */ public static Pattern getMelonPattern() { - return new SingleBlockPattern(new BaseBlock(BlockID.MELON_BLOCK)); + return new BlockPattern(new BaseBlock(BlockID.MELON_BLOCK)); } } diff --git a/src/main/java/com/sk89q/worldedit/function/mask/AbstractExtentMask.java b/src/main/java/com/sk89q/worldedit/function/mask/AbstractExtentMask.java new file mode 100644 index 000000000..7e11ece0c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/AbstractExtentMask.java @@ -0,0 +1,61 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function.mask; + +import com.sk89q.worldedit.extent.Extent; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An abstract implementation of {@link Mask} that takes uses an {@link Extent}. + */ +public abstract class AbstractExtentMask extends AbstractMask { + + private Extent extent; + + /** + * Construct a new mask. + * + * @param extent the extent + */ + protected AbstractExtentMask(Extent extent) { + setExtent(extent); + } + + /** + * Get the extent. + * + * @return the extent + */ + public Extent getExtent() { + return extent; + } + + /** + * Set the extent. + * + * @param extent the extent + */ + public void setExtent(Extent extent) { + checkNotNull(extent); + this.extent = extent; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/AbstractMask.java b/src/main/java/com/sk89q/worldedit/function/mask/AbstractMask.java new file mode 100644 index 000000000..21c5900df --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/AbstractMask.java @@ -0,0 +1,26 @@ +/* + * 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.function.mask; + +/** + * A base class of {@link Mask} that all masks should inherit from. + */ +public abstract class AbstractMask implements Mask { +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/AbstractMask2D.java b/src/main/java/com/sk89q/worldedit/function/mask/AbstractMask2D.java new file mode 100644 index 000000000..1cffb2d2a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/AbstractMask2D.java @@ -0,0 +1,26 @@ +/* + * 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.function.mask; + +/** + * A base class of {@link Mask2D} that all masks should inherit from. + */ +public abstract class AbstractMask2D implements Mask2D { +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java b/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java new file mode 100644 index 000000000..3791560bf --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java @@ -0,0 +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 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.function.mask; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A mask that checks whether blocks at the given positions are matched by + * a block in a list. + *

+ * This mask checks for both an exact block ID and data value match, as well + * for a block with the same ID but a data value of -1. + */ +public class BlockMask extends AbstractExtentMask { + + private final Set blocks = new HashSet(); + + /** + * Create a new block mask. + * + * @param extent the extent + * @param blocks a list of blocks to match + */ + public BlockMask(Extent extent, Collection blocks) { + super(extent); + checkNotNull(blocks); + this.blocks.addAll(blocks); + } + + /** + * Create a new block mask. + * + * @param extent the extent + * @param block an array of blocks to match + */ + public BlockMask(Extent extent, BaseBlock... block) { + this(extent, Arrays.asList(checkNotNull(block))); + } + + /** + * Add the given blocks to the list of criteria. + * + * @param blocks a list of blocks + */ + public void add(Collection blocks) { + checkNotNull(blocks); + this.blocks.addAll(blocks); + } + + /** + * Add the given blocks to the list of criteria. + * + * @param block an array of blocks + */ + public void add(BaseBlock... block) { + add(Arrays.asList(checkNotNull(block))); + } + + /** + * Get the list of blocks that are tested with. + * + * @return a list of blocks + */ + public Collection getBlocks() { + return blocks; + } + + @Override + public boolean test(Vector vector) { + BaseBlock block = getExtent().getBlock(vector); + return blocks.contains(block) || blocks.contains(new BaseBlock(block.getType(), -1)); + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java b/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java new file mode 100644 index 000000000..e955de42a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java @@ -0,0 +1,52 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function.mask; + +import com.sk89q.worldedit.Vector; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Has the criteria where the Y value of passed positions must be within + * a certain range of Y values (inclusive). + */ +public class BoundedHeightMask extends AbstractMask { + + private final int minY; + private final int maxY; + + /** + * Create a new bounded height mask. + * + * @param minY the minimum Y + * @param maxY the maximum Y (must be equal to or greater than minY) + */ + public BoundedHeightMask(int minY, int maxY) { + checkArgument(minY <= maxY, "minY <= maxY required"); + this.minY = minY; + this.maxY = maxY; + } + + @Override + public boolean test(Vector vector) { + return vector.getY() >= minY && vector.getY() <= maxY; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java b/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java new file mode 100644 index 000000000..f6ec67458 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java @@ -0,0 +1,46 @@ +/* + * 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.function.mask; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BlockID; + +/** + * A mask that returns true whenever the block at the location is not + * an air block (it contains some other block). + */ +public class ExistingBlockMask extends AbstractExtentMask { + + /** + * Create a new existing block map. + * + * @param extent the extent to check + */ + public ExistingBlockMask(Extent extent) { + super(extent); + } + + @Override + public boolean test(Vector vector) { + return getExtent().getLazyBlock(vector).getType() != BlockID.AIR; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/FuzzyBlockMask.java b/src/main/java/com/sk89q/worldedit/function/mask/FuzzyBlockMask.java new file mode 100644 index 000000000..e015c7d12 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/FuzzyBlockMask.java @@ -0,0 +1,46 @@ +/* + * 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.function.mask; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; + +import java.util.Collection; + +public class FuzzyBlockMask extends BlockMask { + + public FuzzyBlockMask(Extent extent, Collection blocks) { + super(extent, blocks); + } + + public FuzzyBlockMask(Extent extent, BaseBlock... block) { + super(extent, block); + } + + @Override + public boolean test(Vector vector) { + Extent extent = getExtent(); + Collection blocks = getBlocks(); + BaseBlock lazyBlock = extent.getLazyBlock(vector); + BaseBlock compare = new BaseBlock(lazyBlock.getType(), lazyBlock.getData()); + return BaseBlock.containsFuzzy(blocks, compare); + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/Mask.java b/src/main/java/com/sk89q/worldedit/function/mask/Mask.java new file mode 100644 index 000000000..12d9931b5 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/Mask.java @@ -0,0 +1,37 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function.mask; + +import com.sk89q.worldedit.Vector; + +/** + * Tests whether a given vector meets a criteria. + */ +public interface Mask { + + /** + * Returns true if the criteria is met. + * + * @param vector the vector to test + * @return true if the criteria is met + */ + boolean test(Vector vector); + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/Mask2D.java b/src/main/java/com/sk89q/worldedit/function/mask/Mask2D.java new file mode 100644 index 000000000..e1b12a84f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/Mask2D.java @@ -0,0 +1,37 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function.mask; + +import com.sk89q.worldedit.Vector2D; + +/** + * Tests whether a given vector meets a criteria. + */ +public interface Mask2D { + + /** + * Returns true if the criteria is met. + * + * @param vector the vector to test + * @return true if the criteria is met + */ + boolean test(Vector2D vector); + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection.java b/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection.java new file mode 100644 index 000000000..3185b42c8 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection.java @@ -0,0 +1,102 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function.mask; + +import com.sk89q.worldedit.Vector; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Combines several masks and requires that all masks return true + * when a certain position is tested. It serves as a logical AND operation + * on a list of masks. + */ +public class MaskIntersection extends AbstractMask { + + private final Set masks = new HashSet(); + + /** + * Create a new intersection. + * + * @param masks a list of masks + */ + public MaskIntersection(Collection masks) { + checkNotNull(masks); + this.masks.addAll(masks); + } + + /** + * Create a new intersection. + * + * @param mask a list of masks + */ + public MaskIntersection(Mask... mask) { + this(Arrays.asList(checkNotNull(mask))); + } + + /** + * Add some masks to the list. + * + * @param masks the masks + */ + public void add(Collection masks) { + checkNotNull(masks); + this.masks.addAll(masks); + } + + /** + * Add some masks to the list. + * + * @param mask the masks + */ + public void add(Mask... mask) { + add(Arrays.asList(checkNotNull(mask))); + } + + /** + * Get the masks that are tested with. + * + * @return the masks + */ + public Collection getMasks() { + return masks; + } + + @Override + public boolean test(Vector vector) { + if (masks.size() == 0) { + return false; + } + + for (Mask mask : masks) { + if (!mask.test(vector)) { + return false; + } + } + + return true; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java b/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java new file mode 100644 index 000000000..3ab29c600 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java @@ -0,0 +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 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.function.mask; + +import com.sk89q.worldedit.Vector; + +import java.util.Collection; + +/** + * Combines several masks and requires that one or more masks return true + * when a certain position is tested. It serves as a logical OR operation + * on a list of masks. + */ +public class MaskUnion extends MaskIntersection { + + /** + * Create a new union. + * + * @param masks a list of masks + */ + public MaskUnion(Collection masks) { + super(masks); + } + + /** + * Create a new union. + * + * @param mask a list of masks + */ + public MaskUnion(Mask... mask) { + super(mask); + } + + @Override + public boolean test(Vector vector) { + Collection masks = getMasks(); + + for (Mask mask : masks) { + if (mask.test(vector)) { + return true; + } + } + + return false; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/Masks.java b/src/main/java/com/sk89q/worldedit/function/mask/Masks.java new file mode 100644 index 000000000..97869b241 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/Masks.java @@ -0,0 +1,159 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function.mask; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.session.request.Request; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Various utility functions related to {@link Mask} and {@link Mask2D}. + */ +public final class Masks { + + private Masks() { + } + + /** + * Return a 3D mask that always returns true; + * + * @return a mask + */ + public static Mask alwaysTrue() { + return new AbstractMask() { + @Override + public boolean test(Vector vector) { + return true; + } + }; + } + + /** + * Return a 2D mask that always returns true; + * + * @return a mask + */ + public static Mask2D alwaysTrue2D() { + return new AbstractMask2D() { + @Override + public boolean test(Vector2D vector) { + return true; + } + }; + } + + /** + * Negate the given mask. + * + * @param mask the mask + * @return a new mask + */ + public static Mask negate(final Mask mask) { + checkNotNull(mask); + return new AbstractMask() { + @Override + public boolean test(Vector vector) { + return !mask.test(vector); + } + }; + } + + /** + * Negate the given mask. + * + * @param mask the mask + * @return a new mask + */ + public static Mask2D negate(final Mask2D mask) { + checkNotNull(mask); + return new AbstractMask2D() { + @Override + public boolean test(Vector2D vector) { + return !mask.test(vector); + } + }; + } + + /** + * Wrap an old-style mask and convert it to a new mask. + *

+ * Note, however, that this is strongly not recommended because + * {@link com.sk89q.worldedit.masks.Mask#prepare(LocalSession, LocalPlayer, Vector)} + * is not called. + * + * @param mask the old-style mask + * @param editSession the edit session to bind to + * @return a new-style mask + * @deprecated Please avoid if possible + */ + @Deprecated + @SuppressWarnings("deprecation") + public static Mask wrap(final com.sk89q.worldedit.masks.Mask mask, final EditSession editSession) { + checkNotNull(mask); + return new AbstractMask() { + @Override + public boolean test(Vector vector) { + return mask.matches(editSession, vector); + } + }; + } + + /** + * Wrap an old-style mask and convert it to a new mask. + *

+ * As an {@link EditSession} is not provided in this case, one will be + * taken from the {@link Request}, if possible. If not possible, then the + * mask will return false. + * + * @param mask the old-style mask + * @return a new-style mask + */ + @SuppressWarnings("deprecation") + public static Mask wrap(final com.sk89q.worldedit.masks.Mask mask) { + checkNotNull(mask); + return new AbstractMask() { + @Override + public boolean test(Vector vector) { + EditSession editSession = Request.request().getEditSession(); + return editSession != null && mask.matches(editSession, vector); + } + }; + } + + /** + * Convert a new-style mask to an old-style mask. + * + * @param mask the new-style mask + * @return an old-style mask + */ + @SuppressWarnings("deprecation") + public static com.sk89q.worldedit.masks.Mask wrap(final Mask mask) { + checkNotNull(mask); + return new com.sk89q.worldedit.masks.AbstractMask() { + @Override + public boolean matches(EditSession editSession, Vector pos) { + Request.request().setEditSession(editSession); + return mask.test(pos); + } + }; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java b/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java new file mode 100644 index 000000000..3cb815771 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java @@ -0,0 +1,92 @@ +/* + * 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.function.mask; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.math.noise.NoiseGenerator; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A mask that uses a noise generator and returns true whenever the noise + * generator returns a value above the given density. + */ +public class NoiseFilter extends AbstractMask { + + private NoiseGenerator noiseGenerator; + private double density; + + /** + * Create a new noise filter. + * + * @param noiseGenerator the noise generator + * @param density the density + */ + public NoiseFilter(NoiseGenerator noiseGenerator, double density) { + setNoiseGenerator(noiseGenerator); + setDensity(density); + } + + /** + * Get the noise generator. + * + * @return the noise generator + */ + public NoiseGenerator getNoiseGenerator() { + return noiseGenerator; + } + + /** + * Set the noise generator. + * + * @param noiseGenerator a noise generator + */ + public void setNoiseGenerator(NoiseGenerator noiseGenerator) { + checkNotNull(noiseGenerator); + this.noiseGenerator = noiseGenerator; + } + + /** + * Get the probability of passing as a number between 0 and 1 (inclusive). + * + * @return the density + */ + public double getDensity() { + return density; + } + + /** + * Set the probability of passing as a number between 0 and 1 (inclusive). + * + * @return the density + */ + public void setDensity(double density) { + checkArgument(density >= 0, "density must be >= 0"); + checkArgument(density <= 1, "density must be >= 1"); + this.density = density; + } + + @Override + public boolean test(Vector vector) { + return noiseGenerator.noise(vector) <= density; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter2D.java b/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter2D.java new file mode 100644 index 000000000..8c74b6cb9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter2D.java @@ -0,0 +1,92 @@ +/* + * 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.function.mask; + +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.math.noise.NoiseGenerator; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A mask that uses a noise generator and returns true whenever the noise + * generator returns a value above the given density. + */ +public class NoiseFilter2D extends AbstractMask2D { + + private NoiseGenerator noiseGenerator; + private double density; + + /** + * Create a new noise filter. + * + * @param noiseGenerator the noise generator + * @param density the density + */ + public NoiseFilter2D(NoiseGenerator noiseGenerator, double density) { + setNoiseGenerator(noiseGenerator); + setDensity(density); + } + + /** + * Get the noise generator. + * + * @return the noise generator + */ + public NoiseGenerator getNoiseGenerator() { + return noiseGenerator; + } + + /** + * Set the noise generator. + * + * @param noiseGenerator a noise generator + */ + public void setNoiseGenerator(NoiseGenerator noiseGenerator) { + checkNotNull(noiseGenerator); + this.noiseGenerator = noiseGenerator; + } + + /** + * Get the probability of passing as a number between 0 and 1 (inclusive). + * + * @return the density + */ + public double getDensity() { + return density; + } + + /** + * Set the probability of passing as a number between 0 and 1 (inclusive). + * + * @return the density + */ + public void setDensity(double density) { + checkArgument(density >= 0, "density must be >= 0"); + checkArgument(density <= 1, "density must be >= 1"); + this.density = density; + } + + @Override + public boolean test(Vector2D pos) { + return noiseGenerator.noise(pos) <= density; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java b/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java new file mode 100644 index 000000000..5767137a1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java @@ -0,0 +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.function.mask; + +import com.sk89q.worldedit.Vector; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Checks whether the provided mask tests true for an offset position. + */ +public class OffsetMask extends AbstractMask { + + private Mask mask; + private Vector offset; + + /** + * Create a new instance. + * + * @param mask the mask + * @param offset the offset + */ + public OffsetMask(Mask mask, Vector offset) { + checkNotNull(mask); + checkNotNull(offset); + this.mask = mask; + this.offset = offset; + } + + /** + * Get the mask. + * + * @return the mask + */ + public Mask getMask() { + return mask; + } + + /** + * Set the mask. + * + * @param mask the mask + */ + public void setMask(Mask mask) { + checkNotNull(mask); + this.mask = mask; + } + + /** + * Get the offset. + * + * @return the offset + */ + public Vector getOffset() { + return offset; + } + + /** + * Set the offset. + * + * @param offset the offset + */ + public void setOffset(Vector offset) { + checkNotNull(offset); + this.offset = offset; + } + + @Override + public boolean test(Vector vector) { + return getMask().test(vector.add(offset)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/RegionMask.java b/src/main/java/com/sk89q/worldedit/function/mask/RegionMask.java new file mode 100644 index 000000000..42a1d5ff0 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/RegionMask.java @@ -0,0 +1,67 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function.mask; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.regions.Region; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A mask that tests whether given positions are contained within a region. + */ +public class RegionMask extends AbstractMask { + + private Region region; + + /** + * Create a new region mask. + * + * @param region the region + */ + public RegionMask(Region region) { + setRegion(region); + } + + /** + * Get the region. + * + * @return the region + */ + public Region getRegion() { + return region; + } + + /** + * Set the region that positions must be contained within. + * + * @param region the region + */ + public void setRegion(Region region) { + checkNotNull(region); + this.region = region; + } + + @Override + public boolean test(Vector vector) { + return region.contains(vector); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/mask/SolidBlockMask.java b/src/main/java/com/sk89q/worldedit/function/mask/SolidBlockMask.java new file mode 100644 index 000000000..c23e5b50f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/mask/SolidBlockMask.java @@ -0,0 +1,40 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function.mask; + +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BlockType; + +public class SolidBlockMask extends AbstractExtentMask { + + public SolidBlockMask(Extent extent) { + super(extent); + } + + @Override + public boolean test(Vector vector) { + Extent extent = getExtent(); + BaseBlock lazyBlock = extent.getLazyBlock(vector); + return !BlockType.canPassThrough(lazyBlock.getType(), lazyBlock.getData()); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/operation/BlockMapEntryPlacer.java b/src/main/java/com/sk89q/worldedit/function/operation/BlockMapEntryPlacer.java new file mode 100644 index 000000000..5a2c43c72 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/operation/BlockMapEntryPlacer.java @@ -0,0 +1,67 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function.operation; + +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extent.Extent; + +import java.util.Iterator; +import java.util.Map; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Sets block from an iterator of {@link Map.Entry} containing a + * {@link BlockVector} as the key and a {@link BaseBlock} as the value. + */ +public class BlockMapEntryPlacer implements Operation { + + private final Extent extent; + private final Iterator> iterator; + + /** + * Create a new instance. + * + * @param extent the extent to set the blocks on + * @param iterator the iterator + */ + public BlockMapEntryPlacer(Extent extent, Iterator> iterator) { + checkNotNull(extent); + checkNotNull(iterator); + this.extent = extent; + this.iterator = iterator; + } + + @Override + public Operation resume(RunContext run) throws WorldEditException { + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + extent.setBlock(entry.getKey(), entry.getValue()); + } + + return null; + } + + @Override + public void cancel() { + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/operation/ChangeSetExecutor.java b/src/main/java/com/sk89q/worldedit/function/operation/ChangeSetExecutor.java new file mode 100644 index 000000000..f75733bde --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/operation/ChangeSetExecutor.java @@ -0,0 +1,104 @@ +/* + * 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.function.operation; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.history.change.Change; +import com.sk89q.worldedit.history.changeset.ChangeSet; +import com.sk89q.worldedit.history.UndoContext; + +import java.util.Iterator; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Performs an undo or redo from a given {@link ChangeSet}. + */ +public class ChangeSetExecutor implements Operation { + + public enum Type {UNDO, REDO} + + private final Iterator iterator; + private final Type type; + private final UndoContext context; + + /** + * Create a new instance. + * + * @param changeSet the change set + * @param type type of change + * @param context the undo context + */ + private ChangeSetExecutor(ChangeSet changeSet, Type type, UndoContext context) { + checkNotNull(changeSet); + checkNotNull(type); + checkNotNull(context); + + this.type = type; + this.context = context; + + if (type == Type.UNDO) { + iterator = changeSet.backwardIterator(); + } else { + iterator = changeSet.forwardIterator(); + } + } + + @Override + public Operation resume(RunContext run) throws WorldEditException { + while (iterator.hasNext()) { + Change change = iterator.next(); + if (type == Type.UNDO) { + change.undo(context); + } else { + change.redo(context); + } + } + + return null; + } + + @Override + public void cancel() { + } + + /** + * Create a new undo operation. + * + * @param changeSet the change set + * @param context an undo context + * @return an operation + */ + public static ChangeSetExecutor createUndo(ChangeSet changeSet, UndoContext context) { + return new ChangeSetExecutor(changeSet, Type.UNDO, context); + } + + /** + * Create a new redo operation. + * + * @param changeSet the change set + * @param context an undo context + * @return an operation + */ + public static ChangeSetExecutor createRedo(ChangeSet changeSet, UndoContext context) { + return new ChangeSetExecutor(changeSet, Type.REDO, context); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/operation/DelegateOperation.java b/src/main/java/com/sk89q/worldedit/function/operation/DelegateOperation.java new file mode 100644 index 000000000..d3408069b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/operation/DelegateOperation.java @@ -0,0 +1,60 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function.operation; + +import com.sk89q.worldedit.WorldEditException; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Executes a delegete operation, but returns to another operation upon + * completing the delegate. + */ +public class DelegateOperation implements Operation { + + private final Operation original; + private Operation delegate; + + /** + * Create a new operation delegate. + * + * @param original the operation to return to + * @param delegate the delegate operation to complete before returning + */ + public DelegateOperation(Operation original, Operation delegate) { + checkNotNull(original); + checkNotNull(delegate); + this.original = original; + this.delegate = delegate; + } + + @Override + public Operation resume(RunContext run) throws WorldEditException { + delegate = delegate.resume(run); + return delegate != null ? this : original; + } + + @Override + public void cancel() { + delegate.cancel(); + original.cancel(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java b/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java new file mode 100644 index 000000000..3ebb794ea --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java @@ -0,0 +1,201 @@ +/* + * 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.function.operation; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.CombinedRegionFunction; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.RegionMaskingFilter; +import com.sk89q.worldedit.function.block.ExtentBlockCopy; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.Masks; +import com.sk89q.worldedit.function.visitor.RegionVisitor; +import com.sk89q.worldedit.math.transform.Identity; +import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.regions.Region; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Makes a copy of a portion of one extent to another extent or another point. + *

+ * This is a forward extent copy, meaning that it iterates over the blocks in the + * source extent, and will copy as many blocks as there are in the source. + * Therefore, interpolation will not occur to fill in the gaps. + */ +public class ForwardExtentCopy implements Operation { + + private final Extent source; + private final Extent destination; + private final Region region; + private final Vector to; + private int repetitions = 1; + private Mask sourceMask = Masks.alwaysTrue(); + private RegionFunction sourceFunction = null; + private Transform transform = new Identity(); + private Transform currentTransform = null; + private RegionVisitor lastVisitor; + private int affected; + + /** + * Create a new copy. + * + * @param source the source extent + * @param region the region to copy + * @param destination the destination extent + * @param to the destination position, starting from the the lowest X, Y, Z + */ + public ForwardExtentCopy(Extent source, Region region, Extent destination, Vector to) { + checkNotNull(source); + checkNotNull(region); + checkNotNull(destination); + checkNotNull(to); + this.source = source; + this.destination = destination; + this.region = region; + this.to = to; + } + + /** + * Get the transformation that will occur on every point. + *

+ * The transformation will stack with each repetition. + * + * @return a transformation + */ + public Transform getTransform() { + return transform; + } + + /** + * Set the transformation that will occur on every point. + * + * @param transform a transformation + * @see #getTransform() + */ + public void setTransform(Transform transform) { + checkNotNull(transform); + this.transform = transform; + } + + /** + * Get the mask that gets applied to the source extent. + *

+ * This mask can be used to filter what will be copied from the source. + * + * @return a source mask + */ + public Mask getSourceMask() { + return sourceMask; + } + + /** + * Set a mask that gets applied to the source extent. + * + * @param sourceMask a source mask + * @see #getSourceMask() + */ + public void setSourceMask(Mask sourceMask) { + checkNotNull(sourceMask); + this.sourceMask = sourceMask; + } + + /** + * Get the function that gets applied to all source blocks after + * the copy has been made. + * + * @return a source function, or null if none is to be applied + */ + public RegionFunction getSourceFunction() { + return sourceFunction; + } + + /** + * Set the function that gets applied to all source blocks after + * the copy has been made. + * + * @param function a source function, or null if none is to be applied + */ + public void setSourceFunction(RegionFunction function) { + this.sourceFunction = function; + } + + /** + * Get the number of repetitions left. + * + * @return the number of repetitions + */ + public int getRepetitions() { + return repetitions; + } + + /** + * Set the number of repetitions left. + * + * @param repetitions the number of repetitions + */ + public void setRepetitions(int repetitions) { + checkArgument(repetitions >= 0, "number of repetitions must be non-negative"); + this.repetitions = repetitions; + } + + /** + * Get the number of affected objects. + * + * @return the number of affected + */ + public int getAffected() { + return affected; + } + + @Override + public Operation resume(RunContext run) throws WorldEditException { + if (lastVisitor != null) { + affected += lastVisitor.getAffected(); + lastVisitor = null; + } + + if (repetitions > 0) { + repetitions--; + + if (currentTransform == null) { + currentTransform = transform; + } + + ExtentBlockCopy copy = new ExtentBlockCopy(source, region.getMinimumPoint(), destination, to, currentTransform); + RegionMaskingFilter filter = new RegionMaskingFilter(sourceMask, copy); + RegionFunction function = sourceFunction != null ? new CombinedRegionFunction(filter, sourceFunction) : filter; + RegionVisitor visitor = new RegionVisitor(region, function); + lastVisitor = visitor; + currentTransform = currentTransform.combine(transform); + return new DelegateOperation(this, visitor); + } else { + return null; + } + } + + @Override + public void cancel() { + } + +} diff --git a/src/main/java/com/sk89q/worldedit/operation/Operation.java b/src/main/java/com/sk89q/worldedit/function/operation/Operation.java similarity index 59% rename from src/main/java/com/sk89q/worldedit/operation/Operation.java rename to src/main/java/com/sk89q/worldedit/function/operation/Operation.java index 0e6fc5f11..6e43f2df4 100644 --- a/src/main/java/com/sk89q/worldedit/operation/Operation.java +++ b/src/main/java/com/sk89q/worldedit/function/operation/Operation.java @@ -17,32 +17,35 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.operation; +package com.sk89q.worldedit.function.operation; import com.sk89q.worldedit.WorldEditException; /** - * An task that may be split into multiple steps to be run sequentially immediately - * or at a varying or fixed interval. Operations should attempt to break apart tasks - * into smaller tasks that can be completed in quicker successions. + * An task that may be split into multiple steps to be run sequentially + * immediately or at a varying or fixed interval. Operations should attempt + * to break apart tasks into smaller tasks that can be completed in quicker + * successions. */ public interface Operation { /** - * Complete the next step. If this method returns true, then the method may be - * called again in the future, or possibly never. If this method returns false, - * then this method should not be called again. + * Complete the next step. If this method returns true, then the method may + * be called again in the future, or possibly never. If this method + * returns false, then this method should not be called again. * + * @param run describes information about the current run * @return another operation to run that operation again, or null to stop * @throws WorldEditException an error */ - Operation resume() throws WorldEditException; + Operation resume(RunContext run) throws WorldEditException; /** - * Abort the current task. After the this method is called, {@link #resume()} should - * not be called at any point in the future. This method should not be called after - * successful completion of the operation. This method must be called if - * the operation is interrupted before completion. + * Abort the current task. After the this method is called, + * {@link #resume(RunContext)} should not be called at any point in the + * future. This method should not be called after successful completion of + * the operation. This method must be called if the operation is + * interrupted before completion. */ void cancel(); diff --git a/src/main/java/com/sk89q/worldedit/function/operation/OperationQueue.java b/src/main/java/com/sk89q/worldedit/function/operation/OperationQueue.java new file mode 100644 index 000000000..fafc8a5c6 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/operation/OperationQueue.java @@ -0,0 +1,103 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function.operation; + +import com.sk89q.worldedit.WorldEditException; + +import java.util.ArrayDeque; +import java.util.Collection; +import java.util.Deque; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Executes multiple queues in order. + */ +public class OperationQueue implements Operation { + + private final Deque queue = new ArrayDeque(); + private Operation current; + + /** + * Create a new queue containing no operations. + */ + public OperationQueue() { + } + + /** + * Create a new queue with operations from the given collection. + * + * @param operations a collection of operations + */ + public OperationQueue(Collection operations) { + checkNotNull(operations); + for (Operation operation : operations) { + offer(operation); + } + } + + /** + * Create a new queue with operations from the given array. + * + * @param operation an array of operations + */ + public OperationQueue(Operation... operation) { + checkNotNull(operation); + for (Operation o : operation) { + offer(o); + } + } + + /** + * Add a new operation to the queue. + * + * @param operation the operation + */ + public void offer(Operation operation) { + checkNotNull(operation); + queue.offer(operation); + } + + @Override + public Operation resume(RunContext run) throws WorldEditException { + if (current == null && queue.size() > 0) { + current = queue.poll(); + } + + if (current != null) { + current = current.resume(run); + + if (current == null) { + current = queue.poll(); + } + } + + return current != null ? this : null; + } + + @Override + public void cancel() { + for (Operation operation : queue) { + operation.cancel(); + } + queue.clear(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/operation/OperationHelper.java b/src/main/java/com/sk89q/worldedit/function/operation/Operations.java similarity index 72% rename from src/main/java/com/sk89q/worldedit/operation/OperationHelper.java rename to src/main/java/com/sk89q/worldedit/function/operation/Operations.java index 76c372445..b2582ff4a 100644 --- a/src/main/java/com/sk89q/worldedit/operation/OperationHelper.java +++ b/src/main/java/com/sk89q/worldedit/function/operation/Operations.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.operation; +package com.sk89q.worldedit.function.operation; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.WorldEditException; @@ -25,9 +25,9 @@ import com.sk89q.worldedit.WorldEditException; /** * Operation helper methods. */ -public final class OperationHelper { +public final class Operations { - private OperationHelper() { + private Operations() { } /** @@ -38,7 +38,7 @@ public final class OperationHelper { */ public static void complete(Operation op) throws WorldEditException { while (op != null) { - op = op.resume(); + op = op.resume(new RunContext()); } } @@ -52,7 +52,7 @@ public final class OperationHelper { public static void completeLegacy(Operation op) throws MaxChangedBlocksException { while (op != null) { try { - op = op.resume(); + op = op.resume(new RunContext()); } catch (MaxChangedBlocksException e) { throw e; } catch (WorldEditException e) { @@ -61,4 +61,21 @@ public final class OperationHelper { } } + /** + * Complete a given operation synchronously until it completes. Re-throw all + * {@link com.sk89q.worldedit.WorldEditException} exceptions as + * {@link java.lang.RuntimeException}s. + * + * @param op operation to execute + */ + public static void completeBlindly(Operation op) { + while (op != null) { + try { + op = op.resume(new RunContext()); + } catch (WorldEditException e) { + throw new RuntimeException(e); + } + } + } + } diff --git a/src/main/java/com/sk89q/worldedit/function/operation/RunContext.java b/src/main/java/com/sk89q/worldedit/function/operation/RunContext.java new file mode 100644 index 000000000..d77887e41 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/operation/RunContext.java @@ -0,0 +1,38 @@ +/* + * 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.function.operation; + +/** + * Describes the current run. + */ +public class RunContext { + + /** + * Return whether the current operation should still continue running. + *

+ * This method can be called frequently. + * + * @return true if the operation should continue running + */ + public boolean shouldContinue() { + return true; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/pattern/AbstractPattern.java b/src/main/java/com/sk89q/worldedit/function/pattern/AbstractPattern.java new file mode 100644 index 000000000..bfe05592f --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/pattern/AbstractPattern.java @@ -0,0 +1,26 @@ +/* + * 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.function.pattern; + +/** + * An abstract implementation for {@link Pattern}s. + */ +public abstract class AbstractPattern implements Pattern { +} diff --git a/src/main/java/com/sk89q/worldedit/function/pattern/BlockPattern.java b/src/main/java/com/sk89q/worldedit/function/pattern/BlockPattern.java new file mode 100644 index 000000000..ac363d341 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/pattern/BlockPattern.java @@ -0,0 +1,67 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function.pattern; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A pattern that returns the same {@link BaseBlock} each time. + */ +public class BlockPattern extends AbstractPattern { + + private BaseBlock block; + + /** + * Create a new pattern with the given block. + * + * @param block the block + */ + public BlockPattern(BaseBlock block) { + setBlock(block); + } + + /** + * Get the block. + * + * @return the block that is always returned + */ + public BaseBlock getBlock() { + return block; + } + + /** + * Set the block that is returned. + * + * @param block the block + */ + public void setBlock(BaseBlock block) { + checkNotNull(block); + this.block = block; + } + + @Override + public BaseBlock apply(Vector position) { + return block; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/pattern/ClipboardPattern.java b/src/main/java/com/sk89q/worldedit/function/pattern/ClipboardPattern.java new file mode 100644 index 000000000..0fbed5165 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/pattern/ClipboardPattern.java @@ -0,0 +1,59 @@ +/* + * 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.function.pattern; + +import com.sk89q.worldedit.CuboidClipboard; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A pattern that reads from {@link CuboidClipboard}. + * + * @deprecated May be removed without notice, but there is no direct replacement yet + */ +@Deprecated +public class ClipboardPattern extends AbstractPattern { + + private final CuboidClipboard clipboard; + private final Vector size; + + /** + * Create a new clipboard pattern. + * + * @param clipboard the clipboard + */ + public ClipboardPattern(CuboidClipboard clipboard) { + checkNotNull(clipboard); + this.clipboard = clipboard; + this.size = clipboard.getSize(); + } + + @Override + public BaseBlock apply(Vector position) { + int xp = Math.abs(position.getBlockX()) % size.getBlockX(); + int yp = Math.abs(position.getBlockY()) % size.getBlockY(); + int zp = Math.abs(position.getBlockZ()) % size.getBlockZ(); + + return clipboard.getPoint(new Vector(xp, yp, zp)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java b/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java new file mode 100644 index 000000000..ac51ce464 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java @@ -0,0 +1,38 @@ +/* + * 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.function.pattern; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; + +/** + * Returns a {@link BaseBlock} for a given position. + */ +public interface Pattern { + + /** + * Return a {@link BaseBlock} for the given position. + * + * @param position the position + * @return a block + */ + BaseBlock apply(Vector position); + +} diff --git a/src/main/java/com/sk89q/worldedit/function/pattern/Patterns.java b/src/main/java/com/sk89q/worldedit/function/pattern/Patterns.java new file mode 100644 index 000000000..1375b2209 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/pattern/Patterns.java @@ -0,0 +1,72 @@ +/* + * 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.function.pattern; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Utility methods related to {@link Pattern}s. + */ +public final class Patterns { + + private Patterns() { + } + + /** + * Wrap an old-style pattern and return a new pattern. + * + * @param pattern the pattern + * @return a new-style pattern + */ + public static Pattern wrap(final com.sk89q.worldedit.patterns.Pattern pattern) { + checkNotNull(pattern); + return new Pattern() { + @Override + public BaseBlock apply(Vector position) { + return pattern.next(position); + } + }; + } + + /** + * Wrap a new-style pattern and return an old-style pattern. + * + * @param pattern the pattern + * @return an old-style pattern + */ + public static com.sk89q.worldedit.patterns.Pattern wrap(final Pattern pattern) { + checkNotNull(pattern); + return new com.sk89q.worldedit.patterns.Pattern() { + @Override + public BaseBlock next(Vector position) { + return pattern.apply(position); + } + + @Override + public BaseBlock next(int x, int y, int z) { + return next(new Vector(x, y, z)); + } + }; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java b/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java new file mode 100644 index 000000000..c90dbc534 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java @@ -0,0 +1,88 @@ +/* + * 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.function.pattern; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Uses a random pattern of a weighted list of patterns. + */ +public class RandomPattern extends AbstractPattern { + + private final Random random = new Random(); + private List patterns = new ArrayList(); + private double max = 0; + + /** + * Add a pattern to the weight list of patterns. + *

+ * The probability for the pattern added is chance / max where max is the sum + * of the probabilities of all added patterns. + * + * @param pattern the pattern + * @param chance the chance, which can be any positive number + */ + public void add(Pattern pattern, double chance) { + checkNotNull(pattern); + patterns.add(new Chance(pattern, chance)); + max += chance; + } + + @Override + public BaseBlock apply(Vector position) { + double r = random.nextDouble(); + double offset = 0; + + for (Chance chance : patterns) { + if (r <= (offset + chance.getChance()) / max) { + return chance.getPattern().apply(position); + } + offset += chance.getChance(); + } + + throw new RuntimeException("ProportionalFillPattern"); + } + + private static class Chance { + private Pattern pattern; + private double chance; + + private Chance(Pattern pattern, double chance) { + this.pattern = pattern; + this.chance = chance; + } + + public Pattern getPattern() { + return pattern; + } + + public double getChance() { + return chance; + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java b/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java new file mode 100644 index 000000000..5585ec999 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java @@ -0,0 +1,95 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function.pattern; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extent.Extent; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Returns the blocks from {@link Extent}, repeating when out of bounds. + */ +public class RepeatingExtentPattern extends AbstractPattern { + + private Extent extent; + private Vector offset; + + /** + * Create a new instance. + * + * @param extent the extent + * @param offset the offset + */ + public RepeatingExtentPattern(Extent extent, Vector offset) { + setExtent(extent); + setOffset(offset); + } + + /** + * Get the extent. + * + * @return the extent + */ + public Extent getExtent() { + return extent; + } + + /** + * Set the extent. + * + * @param extent the extent + */ + public void setExtent(Extent extent) { + checkNotNull(extent); + this.extent = extent; + } + + /** + * Get the offset. + * + * @return the offset + */ + public Vector getOffset() { + return offset; + } + + /** + * Set the offset. + * + * @param offset the offset + */ + public void setOffset(Vector offset) { + checkNotNull(offset); + this.offset = offset; + } + + @Override + public BaseBlock apply(Vector position) { + Vector base = position.add(offset); + Vector size = extent.getMaximumPoint().subtract(extent.getMinimumPoint()); + int x = base.getBlockX() % size.getBlockX(); + int y = base.getBlockY() % size.getBlockY(); + int z = base.getBlockZ() % size.getBlockZ(); + return extent.getBlock(new Vector(x, y, z)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/util/FlatRegionOffset.java b/src/main/java/com/sk89q/worldedit/function/util/FlatRegionOffset.java new file mode 100644 index 000000000..a51b2800d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/util/FlatRegionOffset.java @@ -0,0 +1,71 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function.util; + +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.FlatRegionFunction; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Offsets the position parameter by adding a given offset vector. + */ +public class FlatRegionOffset implements FlatRegionFunction { + + private Vector2D offset; + private final FlatRegionFunction function; + + /** + * Create a new instance. + * + * @param offset the offset + * @param function the function that is called with the offset position + */ + public FlatRegionOffset(Vector2D offset, FlatRegionFunction function) { + checkNotNull(function); + setOffset(offset); + this.function = function; + } + + /** + * Get the offset that is added to the position. + * + * @return the offset + */ + public Vector2D getOffset() { + return offset; + } + + /** + * Set the offset that is added to the position. + * + * @param offset the offset + */ + public void setOffset(Vector2D offset) { + checkNotNull(offset); + this.offset = offset; + } + + @Override + public boolean apply(Vector2D position) throws WorldEditException { + return function.apply(position.add(offset)); + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/util/RegionOffset.java b/src/main/java/com/sk89q/worldedit/function/util/RegionOffset.java new file mode 100644 index 000000000..b9d063d62 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/util/RegionOffset.java @@ -0,0 +1,72 @@ +/* + * 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.function.util; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.RegionFunction; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Offsets the position parameter by adding a given offset vector. + */ +public class RegionOffset implements RegionFunction { + + private Vector offset; + private final RegionFunction function; + + /** + * Create a new instance. + * + * @param offset the offset + * @param function the function that is called with the offset position + */ + public RegionOffset(Vector offset, RegionFunction function) { + checkNotNull(function); + setOffset(offset); + this.function = function; + } + + /** + * Get the offset that is added to the position. + * + * @return the offset + */ + public Vector getOffset() { + return offset; + } + + /** + * Set the offset that is added to the position. + * + * @param offset the offset + */ + public void setOffset(Vector offset) { + checkNotNull(offset); + this.offset = offset; + } + + @Override + public boolean apply(Vector position) throws WorldEditException { + return function.apply(position.add(offset)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java b/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java new file mode 100644 index 000000000..f7d60a3ca --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java @@ -0,0 +1,178 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function.visitor; + +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.operation.RunContext; + +import java.util.*; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Performs a breadth-first search starting from points added with + * {@link #visit(com.sk89q.worldedit.Vector)}. The search continues + * to a certain adjacent point provided that the method + * {@link #isVisitable(com.sk89q.worldedit.Vector, com.sk89q.worldedit.Vector)} + * returns true for that point. + *

+ * As an abstract implementation, this class can be used to implement + * functionality that starts at certain points and extends outward from + * those points. + */ +public abstract class BreadthFirstSearch implements Operation { + + private final RegionFunction function; + private final Queue queue = new ArrayDeque(); + private final Set visited = new HashSet(); + private final List directions = new ArrayList(); + private int affected = 0; + + /** + * Create a new instance. + * + * @param function the function to apply to visited blocks + */ + protected BreadthFirstSearch(RegionFunction function) { + checkNotNull(function); + this.function = function; + addAxes(); + } + + /** + * Get the list of directions will be visited. + *

+ * Directions are {@link com.sk89q.worldedit.Vector}s that determine + * what adjacent points area available. Vectors should not be + * unit vectors. An example of a valid direction is {@code new Vector(1, 0, 1)}. + *

+ * The list of directions can be cleared. + * + * @return the list of directions + */ + protected Collection getDirections() { + return directions; + } + + /** + * Add the directions along the axes as directions to visit. + */ + protected void addAxes() { + directions.add(new Vector(0, -1, 0)); + directions.add(new Vector(0, 1, 0)); + directions.add(new Vector(-1, 0, 0)); + directions.add(new Vector(1, 0, 0)); + directions.add(new Vector(0, 0, -1)); + directions.add(new Vector(0, 0, 1)); + } + + /** + * Add the diagonal directions as directions to visit. + */ + protected void addDiagonal() { + directions.add(new Vector(1, 0, 1)); + directions.add(new Vector(-1, 0, -1)); + directions.add(new Vector(1, 0, -1)); + directions.add(new Vector(-1, 0, 1)); + } + + /** + * Add the given location to the list of locations to visit, provided + * that it has not been visited. The position passed to this method + * will still be visited even if it fails + * {@link #isVisitable(com.sk89q.worldedit.Vector, com.sk89q.worldedit.Vector)}. + *

+ * This method should be used before the search begins, because if + * the position does fail the test, and the search has already + * visited it (because it is connected to another root point), + * the search will mark the position as "visited" and a call to this + * method will do nothing. + * + * @param position the position + */ + public void visit(Vector position) { + BlockVector blockVector = position.toBlockVector(); + if (!visited.contains(blockVector)) { + queue.add(blockVector); + visited.add(blockVector); + } + } + + /** + * Try to visit the given 'to' location. + * + * @param from the origin block + * @param to the block under question + */ + private void visit(Vector from, Vector to) { + BlockVector blockVector = to.toBlockVector(); + if (!visited.contains(blockVector)) { + visited.add(blockVector); + if (isVisitable(from, to)) { + queue.add(blockVector); + } + } + } + + /** + * Return whether the given 'to' block should be visited, starting from the + * 'from' block. + * + * @param from the origin block + * @param to the block under question + * @return true if the 'to' block should be visited + */ + protected abstract boolean isVisitable(Vector from, Vector to); + + /** + * Get the number of affected objects. + * + * @return the number of affected + */ + public int getAffected() { + return affected; + } + + @Override + public Operation resume(RunContext run) throws WorldEditException { + Vector position; + + while ((position = queue.poll()) != null) { + if (function.apply(position)) { + affected++; + } + + for (Vector dir : directions) { + visit(position, position.add(dir)); + } + } + + return null; + } + + @Override + public void cancel() { + } + +} \ No newline at end of file diff --git a/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java b/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java new file mode 100644 index 000000000..ce6d1018d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java @@ -0,0 +1,68 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function.visitor; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.mask.Mask; + +import java.util.Collection; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Visits adjacent points on the same X-Z plane as long as the points + * pass the given mask, and then executes the provided region + * function on the entire column. + *

+ * This is used by //fill. + */ +public class DownwardVisitor extends RecursiveVisitor { + + private int baseY; + + /** + * Create a new visitor. + * + * @param mask the mask + * @param function the function + * @param baseY the base Y + */ + public DownwardVisitor(Mask mask, RegionFunction function, int baseY) { + super(mask, function); + checkNotNull(mask); + + this.baseY = baseY; + + Collection directions = getDirections(); + directions.clear(); + directions.add(new Vector(1, 0, 0)); + directions.add(new Vector(-1, 0, 0)); + directions.add(new Vector(0, 0, 1)); + directions.add(new Vector(0, 0, -1)); + directions.add(new Vector(0, -1, 0)); + } + + @Override + protected boolean isVisitable(Vector from, Vector to) { + int fromY = from.getBlockY(); + return (fromY == baseY || to.subtract(from).getBlockY() < 0) && super.isVisitable(from, to); + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/visitor/FlatRegionVisitor.java b/src/main/java/com/sk89q/worldedit/function/visitor/FlatRegionVisitor.java new file mode 100644 index 000000000..5c369d068 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/visitor/FlatRegionVisitor.java @@ -0,0 +1,79 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function.visitor; + +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.FlatRegionFunction; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.RunContext; +import com.sk89q.worldedit.regions.FlatRegion; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Applies region functions to columns in a {@link FlatRegion}. + */ +public class FlatRegionVisitor implements Operation { + + private final FlatRegion flatRegion; + private final FlatRegionFunction function; + private int affected = 0; + + /** + * Create a new visitor. + * + * @param flatRegion a flat region + * @param function a function to apply to columns + */ + public FlatRegionVisitor(FlatRegion flatRegion, FlatRegionFunction function) { + checkNotNull(flatRegion); + checkNotNull(function); + + this.flatRegion = flatRegion; + this.function = function; + } + + /** + * Get the number of affected objects. + * + * @return the number of affected + */ + public int getAffected() { + return affected; + } + + @Override + public Operation resume(RunContext run) throws WorldEditException { + for (Vector2D pt : flatRegion.asFlatRegion()) { + if (function.apply(pt)) { + affected++; + } + } + + return null; + } + + @Override + public void cancel() { + } + +} + diff --git a/src/main/java/com/sk89q/worldedit/function/visitor/LayerVisitor.java b/src/main/java/com/sk89q/worldedit/function/visitor/LayerVisitor.java new file mode 100644 index 000000000..24f7fefc6 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/visitor/LayerVisitor.java @@ -0,0 +1,128 @@ +/* + * 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.function.visitor; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.LayerFunction; +import com.sk89q.worldedit.function.mask.Mask2D; +import com.sk89q.worldedit.function.mask.Masks; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.RunContext; +import com.sk89q.worldedit.regions.FlatRegion; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Visits the layers within a region. + *

+ * This class works by iterating over all the columns in a {@link FlatRegion}, + * finding the first ground block in each column (searching from a given + * maximum Y down to a minimum Y), and then applies a {@link LayerFunction} to + * each layer. + */ +public class LayerVisitor implements Operation { + + private final FlatRegion flatRegion; + private final LayerFunction function; + private Mask2D mask = Masks.alwaysTrue2D(); + private int minY; + private int maxY; + + /** + * Create a new visitor. + * + * @param flatRegion the flat region to visit + * @param minY the minimum Y to stop the search at + * @param maxY the maximum Y to begin the search at + * @param function the layer function to apply t blocks + */ + public LayerVisitor(FlatRegion flatRegion, int minY, int maxY, LayerFunction function) { + checkNotNull(flatRegion); + checkArgument(minY <= maxY, "minY <= maxY required"); + checkNotNull(function); + + this.flatRegion = flatRegion; + this.minY = minY; + this.maxY = maxY; + this.function = function; + } + + /** + * Get the mask that determines which columns within the flat region + * will be visited. + * + * @return a 2D mask + */ + public Mask2D getMask() { + return mask; + } + + /** + * Set the mask that determines which columns within the flat region + * will be visited. + * + * @param mask a 2D mask + */ + public void setMask(Mask2D mask) { + checkNotNull(mask); + this.mask = mask; + } + + @Override + public Operation resume(RunContext run) throws WorldEditException { + for (Vector2D column : flatRegion.asFlatRegion()) { + if (!mask.test(column)) { + continue; + } + + // Abort if we are underground + if (function.isGround(column.toVector(maxY + 1))) { + return null; + } + + boolean found = false; + int groundY = 0; + for (int y = maxY; y >= minY; --y) { + Vector test = column.toVector(y); + if (!found) { + if (function.isGround(test)) { + found = true; + groundY = y; + } + } + + if (found) { + if (!function.apply(test, groundY - y)) { + break; + } + } + } + } + + return null; + } + + @Override + public void cancel() { + } +} diff --git a/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java b/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java new file mode 100644 index 000000000..982d94c68 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java @@ -0,0 +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 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.function.visitor; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.mask.Mask; + +import java.util.Collection; + +/** + * A {@link RecursiveVisitor} that goes orthogonally to the side and down, but never up. + */ +public class NonRisingVisitor extends RecursiveVisitor { + + /** + * Create a new recursive visitor. + * + * @param mask the mask + * @param function the function + */ + public NonRisingVisitor(Mask mask, RegionFunction function) { + super(mask, function); + Collection directions = getDirections(); + directions.clear(); + directions.add(new Vector(1, 0, 0)); + directions.add(new Vector(-1, 0, 0)); + directions.add(new Vector(0, 0, 1)); + directions.add(new Vector(0, 0, -1)); + directions.add(new Vector(0, -1, 0)); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/visitor/RecursiveVisitor.java b/src/main/java/com/sk89q/worldedit/function/visitor/RecursiveVisitor.java new file mode 100644 index 000000000..d6531b933 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/visitor/RecursiveVisitor.java @@ -0,0 +1,52 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.function.visitor; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.mask.Mask; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An implementation of an {@link BreadthFirstSearch} that uses a mask to + * determine where a block should be visited. + */ +public class RecursiveVisitor extends BreadthFirstSearch { + + private final Mask mask; + + /** + * Create a new recursive visitor. + * + * @param mask the mask + * @param function the function + */ + public RecursiveVisitor(Mask mask, RegionFunction function) { + super(function); + checkNotNull(mask); + this.mask = mask; + } + + @Override + protected boolean isVisitable(Vector from, Vector to) { + return mask.test(to); + } +} diff --git a/src/main/java/com/sk89q/worldedit/operation/FlatRegionApplicator.java b/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java similarity index 67% rename from src/main/java/com/sk89q/worldedit/operation/FlatRegionApplicator.java rename to src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java index 0f7d42933..b8fffb5ec 100644 --- a/src/main/java/com/sk89q/worldedit/operation/FlatRegionApplicator.java +++ b/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java @@ -17,31 +17,27 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.operation; +package com.sk89q.worldedit.function.visitor; -import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.regions.FlatRegion; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.operation.RunContext; import com.sk89q.worldedit.regions.Region; /** * Utility class to apply region functions to {@link com.sk89q.worldedit.regions.Region}. */ -public class FlatRegionApplicator implements Operation { +public class RegionVisitor implements Operation { - private final FlatRegion flatRegion; - private final FlatRegionFunction function; + private final Region region; + private final RegionFunction function; private int affected = 0; - public FlatRegionApplicator(Region region, FlatRegionFunction function) { + public RegionVisitor(Region region, RegionFunction function) { + this.region = region; this.function = function; - - if (region instanceof FlatRegion) { - flatRegion = (FlatRegion) region; - } else { - flatRegion = CuboidRegion.makeCuboid(region); - } } /** @@ -54,8 +50,8 @@ public class FlatRegionApplicator implements Operation { } @Override - public Operation resume() throws WorldEditException { - for (Vector2D pt : flatRegion.asFlatRegion()) { + public Operation resume(RunContext run) throws WorldEditException { + for (Vector pt : region) { if (function.apply(pt)) { affected++; } diff --git a/src/main/java/com/sk89q/worldedit/history/UndoContext.java b/src/main/java/com/sk89q/worldedit/history/UndoContext.java new file mode 100644 index 000000000..fbcce2d37 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/history/UndoContext.java @@ -0,0 +1,54 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.history; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.history.change.BlockChange; + +import javax.annotation.Nullable; + +/** + * Provides context for undo and redo operations. + *

+ * For example, {@link BlockChange}s take the {@link Extent} from the + * context rather than store a reference to one. + */ +public class UndoContext { + + private Extent extent; + + /** + * Get the extent set on this context. + * + * @return an extent or null + */ + public @Nullable Extent getExtent() { + return extent; + } + + /** + * Set the extent on this context. + * + * @param extent an extent or null + */ + public void setExtent(@Nullable Extent extent) { + this.extent = extent; + } +} diff --git a/src/main/java/com/sk89q/worldedit/history/change/BlockChange.java b/src/main/java/com/sk89q/worldedit/history/change/BlockChange.java new file mode 100644 index 000000000..415d7d669 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/history/change/BlockChange.java @@ -0,0 +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 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.history.change; + +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.history.UndoContext; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Represents a block change that may be undone or replayed. + *

+ * This block change does not have an {@link Extent} assigned to it because + * one will be taken from the passed {@link UndoContext}. If the context + * does not have an extent (it is null), cryptic errors may occur. + */ +public class BlockChange implements Change { + + private final BlockVector position; + private final BaseBlock previous; + private final BaseBlock current; + + /** + * Create a new block change. + * + * @param position the position + * @param previous the previous block + * @param current the current block + */ + public BlockChange(BlockVector position, BaseBlock previous, BaseBlock current) { + checkNotNull(position); + checkNotNull(previous); + checkNotNull(current); + this.position = position; + this.previous = previous; + this.current = current; + } + + /** + * Get the position. + * + * @return the position + */ + public BlockVector getPosition() { + return position; + } + + /** + * Get the previous block. + * + * @return the previous block + */ + public BaseBlock getPrevious() { + return previous; + } + + /** + * Get the current block. + * + * @return the current block + */ + public BaseBlock getCurrent() { + return current; + } + + @Override + public void undo(UndoContext context) throws WorldEditException { + checkNotNull(context.getExtent()).setBlock(position, previous); + } + + @Override + public void redo(UndoContext context) throws WorldEditException { + checkNotNull(context.getExtent()).setBlock(position, current); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/history/change/Change.java b/src/main/java/com/sk89q/worldedit/history/change/Change.java new file mode 100644 index 000000000..6f6e121dd --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/history/change/Change.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.history.change; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.history.changeset.ChangeSet; +import com.sk89q.worldedit.history.UndoContext; + +/** + * Describes a change that can be undone or re-applied. + */ +public interface Change { + + /** + * Perform an undo. This method may not be available if the object + * was returned from {@link ChangeSet#forwardIterator()}. + * + * @param context a context for undo + * @throws WorldEditException on an error + */ + void undo(UndoContext context) throws WorldEditException; + + /** + * Perform an redo. This method may not be available if the object + * was returned from {@link ChangeSet#backwardIterator()} ()}. + * + * @param context a context for redo + * @throws WorldEditException on an error + */ + void redo(UndoContext context) throws WorldEditException; + +} diff --git a/src/main/java/com/sk89q/worldedit/history/changeset/ArrayListHistory.java b/src/main/java/com/sk89q/worldedit/history/changeset/ArrayListHistory.java new file mode 100644 index 000000000..8338bf946 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/history/changeset/ArrayListHistory.java @@ -0,0 +1,59 @@ +/* + * 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.history.changeset; + +import com.google.common.collect.Lists; +import com.sk89q.worldedit.history.change.Change; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Stores all {@link Change}s in an {@link ArrayList}. + */ +public class ArrayListHistory implements ChangeSet { + + private final List changes = new ArrayList(); + + @Override + public void add(Change change) { + checkNotNull(change); + changes.add(change); + } + + @Override + public Iterator backwardIterator() { + return Lists.reverse(changes).iterator(); + } + + @Override + public Iterator forwardIterator() { + return changes.iterator(); + } + + @Override + public int size() { + return changes.size(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/history/changeset/BlockOptimizedHistory.java b/src/main/java/com/sk89q/worldedit/history/changeset/BlockOptimizedHistory.java new file mode 100644 index 000000000..919b19b65 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/history/changeset/BlockOptimizedHistory.java @@ -0,0 +1,97 @@ +/* + * 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.history.changeset; + +import com.google.common.base.Function; +import com.google.common.collect.Iterators; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.history.change.BlockChange; +import com.sk89q.worldedit.history.change.Change; +import com.sk89q.worldedit.util.collection.TupleArrayList; + +import java.util.ArrayList; +import java.util.Iterator; + +import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.Map.Entry; + +/** + * An extension of {@link ArrayListHistory} that stores {@link BlockChange}s + * separately in two {@link ArrayList}s. + *

+ * Whether this is a good idea or not is highly questionable, but this class + * exists because this is how history was implemented in WorldEdit for + * many years. + */ +public class BlockOptimizedHistory extends ArrayListHistory { + + private final TupleArrayList previous = new TupleArrayList(); + private final TupleArrayList current = new TupleArrayList(); + + @Override + public void add(Change change) { + checkNotNull(change); + + if (change instanceof BlockChange) { + BlockChange blockChange = (BlockChange) change; + BlockVector position = blockChange.getPosition(); + previous.put(position, blockChange.getPrevious()); + current.put(position, blockChange.getCurrent()); + } else { + super.add(change); + } + } + + @Override + public Iterator forwardIterator() { + return Iterators.concat( + super.forwardIterator(), + Iterators.transform(current.iterator(), createTransform())); + } + + @Override + public Iterator backwardIterator() { + return Iterators.concat( + super.backwardIterator(), + Iterators.transform(previous.iterator(true), createTransform())); + } + + @Override + public int size() { + return super.size() + previous.size(); + } + + /** + * Create a function that transforms each entry from the double array lists' iterator + * into an {@link Change}. + * + * @return a function + */ + private Function, Change> createTransform() { + return new Function, Change>() { + @Override + public Change apply(Entry entry) { + return new BlockChange(entry.getKey(), entry.getValue(), entry.getValue()); + } + }; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java b/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java new file mode 100644 index 000000000..7b05af4c5 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java @@ -0,0 +1,66 @@ +/* + * 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.history.changeset; + +import com.sk89q.worldedit.history.change.Change; + +import java.util.Iterator; + +/** + * Tracks a set of undoable operations and allows their undo and redo. The + * entirety of a change set should be undone and redone at once. + */ +public interface ChangeSet { + + /** + * Add the given change to the history. + * + * @param change the change + */ + void add(Change change); + + /** + * Get a backward directed iterator that can be used for undo. + *

+ * The iterator may return the changes out of order, as long as the final + * result after all changes have been applied is correct. + * + * @return a undo directed iterator + */ + Iterator backwardIterator(); + + /** + * Get a forward directed iterator that can be used for redo. + *

+ * The iterator may return the changes out of order, as long as the final + * result after all changes have been applied is correct. + * + * @return a forward directed iterator + */ + Iterator forwardIterator(); + + /** + * Get the number of stored changes. + * + * @return the change count + */ + int size(); + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/InternalEditSessionFactory.java b/src/main/java/com/sk89q/worldedit/internal/InternalEditSessionFactory.java new file mode 100644 index 000000000..308767389 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/InternalEditSessionFactory.java @@ -0,0 +1,70 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.internal; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.EditSessionFactory; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.event.extent.EditSessionEvent; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.util.eventbus.EventBus; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Internal factory for {@link EditSession}s. + */ +@SuppressWarnings("deprecation") +public final class InternalEditSessionFactory extends EditSessionFactory { + + private final EventBus eventBus; + + /** + * Create a new factory. + * + * @param eventBus the event bus + */ + public InternalEditSessionFactory(EventBus eventBus) { + checkNotNull(eventBus); + this.eventBus = eventBus; + } + + @Override + public EditSession getEditSession(LocalWorld world, int maxBlocks) { + return new EditSession(eventBus, world, maxBlocks, null, new EditSessionEvent(world, null, maxBlocks, null)); + } + + @Override + public EditSession getEditSession(LocalWorld world, int maxBlocks, LocalPlayer player) { + return new EditSession(eventBus, world, maxBlocks, null, new EditSessionEvent(world, player, maxBlocks, null)); + } + + @Override + public EditSession getEditSession(LocalWorld world, int maxBlocks, BlockBag blockBag) { + return new EditSession(eventBus, world, maxBlocks, blockBag, new EditSessionEvent(world, null, maxBlocks, null)); + } + + @Override + public EditSession getEditSession(LocalWorld world, int maxBlocks, BlockBag blockBag, LocalPlayer player) { + return new EditSession(eventBus, world, maxBlocks, blockBag, new EditSessionEvent(world, player, maxBlocks, null)); + } + +} \ No newline at end of file diff --git a/src/main/java/com/sk89q/worldedit/cui/CUIEvent.java b/src/main/java/com/sk89q/worldedit/internal/cui/CUIEvent.java similarity index 93% rename from src/main/java/com/sk89q/worldedit/cui/CUIEvent.java rename to src/main/java/com/sk89q/worldedit/internal/cui/CUIEvent.java index f1f85107d..e272fe9f6 100644 --- a/src/main/java/com/sk89q/worldedit/cui/CUIEvent.java +++ b/src/main/java/com/sk89q/worldedit/internal/cui/CUIEvent.java @@ -1,27 +1,27 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.cui; - -public interface CUIEvent { - - public String getTypeId(); - - public String[] getParameters(); -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.cui; + +public interface CUIEvent { + + public String getTypeId(); + + public String[] getParameters(); +} diff --git a/src/main/java/com/sk89q/worldedit/cui/CUIRegion.java b/src/main/java/com/sk89q/worldedit/internal/cui/CUIRegion.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/cui/CUIRegion.java rename to src/main/java/com/sk89q/worldedit/internal/cui/CUIRegion.java index b781304d9..8bdd9e39f 100644 --- a/src/main/java/com/sk89q/worldedit/cui/CUIRegion.java +++ b/src/main/java/com/sk89q/worldedit/internal/cui/CUIRegion.java @@ -1,65 +1,65 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.cui; - -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalSession; - -public interface CUIRegion { - - /** - * Sends CUI events describing the region for - * versions of CUI equal to or greater than the - * value supplied by getProtocolVersion(). - * - */ - public void describeCUI(LocalSession session, LocalPlayer player); - - /** - * Sends CUI events describing the region for - * versions of CUI smaller than the value - * supplied by getProtocolVersion(). - * - */ - public void describeLegacyCUI(LocalSession session, LocalPlayer player); - - /** - * Returns the CUI version that is required to send - * up-to-date data. If the CUI version is smaller than - * this value, the legacy methods will be called. - * - * @return - */ - public int getProtocolVersion(); - - /** - * Returns the type ID to send to CUI in the selection event. - * @return - */ - public String getTypeID(); - - /** - * Returns the type ID to send to CUI in the selection - * event if the CUI is in legacy mode. - * - * @return - */ - public String getLegacyTypeID(); -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.cui; + +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; + +public interface CUIRegion { + + /** + * Sends CUI events describing the region for + * versions of CUI equal to or greater than the + * value supplied by getProtocolVersion(). + * + */ + public void describeCUI(LocalSession session, LocalPlayer player); + + /** + * Sends CUI events describing the region for + * versions of CUI smaller than the value + * supplied by getProtocolVersion(). + * + */ + public void describeLegacyCUI(LocalSession session, LocalPlayer player); + + /** + * Returns the CUI version that is required to send + * up-to-date data. If the CUI version is smaller than + * this value, the legacy methods will be called. + * + * @return + */ + public int getProtocolVersion(); + + /** + * Returns the type ID to send to CUI in the selection event. + * @return + */ + public String getTypeID(); + + /** + * Returns the type ID to send to CUI in the selection + * event if the CUI is in legacy mode. + * + * @return + */ + public String getLegacyTypeID(); +} diff --git a/src/main/java/com/sk89q/worldedit/cui/SelectionCylinderEvent.java b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionCylinderEvent.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/cui/SelectionCylinderEvent.java rename to src/main/java/com/sk89q/worldedit/internal/cui/SelectionCylinderEvent.java index a3fd03475..904d8a794 100644 --- a/src/main/java/com/sk89q/worldedit/cui/SelectionCylinderEvent.java +++ b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionCylinderEvent.java @@ -1,47 +1,47 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.cui; - -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.Vector2D; - -public class SelectionCylinderEvent implements CUIEvent { - - protected final Vector pos; - protected final Vector2D radius; - - public SelectionCylinderEvent(Vector pos, Vector2D radius) { - this.pos = pos; - this.radius = radius; - } - - public String getTypeId() { - return "cyl"; - } - - public String[] getParameters() { - return new String[] { - String.valueOf(pos.getBlockX()), - String.valueOf(pos.getBlockY()), - String.valueOf(pos.getBlockZ()), - String.valueOf(radius.getX()), - String.valueOf(radius.getZ()) - }; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.cui; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; + +public class SelectionCylinderEvent implements CUIEvent { + + protected final Vector pos; + protected final Vector2D radius; + + public SelectionCylinderEvent(Vector pos, Vector2D radius) { + this.pos = pos; + this.radius = radius; + } + + public String getTypeId() { + return "cyl"; + } + + public String[] getParameters() { + return new String[] { + String.valueOf(pos.getBlockX()), + String.valueOf(pos.getBlockY()), + String.valueOf(pos.getBlockZ()), + String.valueOf(radius.getX()), + String.valueOf(radius.getZ()) + }; + } +} diff --git a/src/main/java/com/sk89q/worldedit/cui/SelectionEllipsoidPointEvent.java b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionEllipsoidPointEvent.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/cui/SelectionEllipsoidPointEvent.java rename to src/main/java/com/sk89q/worldedit/internal/cui/SelectionEllipsoidPointEvent.java index 0b3ad9b7e..b770c97e9 100644 --- a/src/main/java/com/sk89q/worldedit/cui/SelectionEllipsoidPointEvent.java +++ b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionEllipsoidPointEvent.java @@ -1,45 +1,45 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.cui; - -import com.sk89q.worldedit.Vector; - -public class SelectionEllipsoidPointEvent implements CUIEvent { - protected final int id; - protected final Vector pos; - - public SelectionEllipsoidPointEvent(int id, Vector pos) { - this.id = id; - this.pos = pos; - } - - public String getTypeId() { - return "e"; - } - - public String[] getParameters() { - return new String[] { - String.valueOf(id), - String.valueOf(pos.getBlockX()), - String.valueOf(pos.getBlockY()), - String.valueOf(pos.getBlockZ()) - }; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.cui; + +import com.sk89q.worldedit.Vector; + +public class SelectionEllipsoidPointEvent implements CUIEvent { + protected final int id; + protected final Vector pos; + + public SelectionEllipsoidPointEvent(int id, Vector pos) { + this.id = id; + this.pos = pos; + } + + public String getTypeId() { + return "e"; + } + + public String[] getParameters() { + return new String[] { + String.valueOf(id), + String.valueOf(pos.getBlockX()), + String.valueOf(pos.getBlockY()), + String.valueOf(pos.getBlockZ()) + }; + } +} diff --git a/src/main/java/com/sk89q/worldedit/cui/SelectionMinMaxEvent.java b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionMinMaxEvent.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/cui/SelectionMinMaxEvent.java rename to src/main/java/com/sk89q/worldedit/internal/cui/SelectionMinMaxEvent.java index faccd8bc2..24ed88692 100644 --- a/src/main/java/com/sk89q/worldedit/cui/SelectionMinMaxEvent.java +++ b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionMinMaxEvent.java @@ -1,43 +1,43 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.cui; - -public class SelectionMinMaxEvent implements CUIEvent { - - protected final int min; - protected final int max; - - public SelectionMinMaxEvent(int min, int max) { - this.min = min; - this.max = max; - } - - public String getTypeId() { - return "mm"; - } - - public String[] getParameters() { - return new String[] { - String.valueOf(min), - String.valueOf(max), - }; - } - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.cui; + +public class SelectionMinMaxEvent implements CUIEvent { + + protected final int min; + protected final int max; + + public SelectionMinMaxEvent(int min, int max) { + this.min = min; + this.max = max; + } + + public String getTypeId() { + return "mm"; + } + + public String[] getParameters() { + return new String[] { + String.valueOf(min), + String.valueOf(max), + }; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/cui/SelectionPoint2DEvent.java b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionPoint2DEvent.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/cui/SelectionPoint2DEvent.java rename to src/main/java/com/sk89q/worldedit/internal/cui/SelectionPoint2DEvent.java index be36dbe61..3f0a9a2ba 100644 --- a/src/main/java/com/sk89q/worldedit/cui/SelectionPoint2DEvent.java +++ b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionPoint2DEvent.java @@ -1,59 +1,59 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.cui; - -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.Vector2D; - -public class SelectionPoint2DEvent implements CUIEvent { - - protected final int id; - protected final int blockx; - protected final int blockz; - protected final int area; - - public SelectionPoint2DEvent(int id, Vector2D pos, int area) { - this.id = id; - this.blockx = pos.getBlockX(); - this.blockz = pos.getBlockZ(); - this.area = area; - } - - public SelectionPoint2DEvent(int id, Vector pos, int area) { - this.id = id; - this.blockx = pos.getBlockX(); - this.blockz = pos.getBlockZ(); - this.area = area; - } - - public String getTypeId() { - return "p2"; - } - - public String[] getParameters() { - return new String[] { - String.valueOf(id), - String.valueOf(blockx), - String.valueOf(blockz), - String.valueOf(area) - }; - } - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.cui; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; + +public class SelectionPoint2DEvent implements CUIEvent { + + protected final int id; + protected final int blockx; + protected final int blockz; + protected final int area; + + public SelectionPoint2DEvent(int id, Vector2D pos, int area) { + this.id = id; + this.blockx = pos.getBlockX(); + this.blockz = pos.getBlockZ(); + this.area = area; + } + + public SelectionPoint2DEvent(int id, Vector pos, int area) { + this.id = id; + this.blockx = pos.getBlockX(); + this.blockz = pos.getBlockZ(); + this.area = area; + } + + public String getTypeId() { + return "p2"; + } + + public String[] getParameters() { + return new String[] { + String.valueOf(id), + String.valueOf(blockx), + String.valueOf(blockz), + String.valueOf(area) + }; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/cui/SelectionPointEvent.java b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionPointEvent.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/cui/SelectionPointEvent.java rename to src/main/java/com/sk89q/worldedit/internal/cui/SelectionPointEvent.java index b19833174..e4fb436f1 100644 --- a/src/main/java/com/sk89q/worldedit/cui/SelectionPointEvent.java +++ b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionPointEvent.java @@ -1,50 +1,50 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.cui; - -import com.sk89q.worldedit.Vector; - -public class SelectionPointEvent implements CUIEvent { - - protected final int id; - protected final Vector pos; - protected final int area; - - public SelectionPointEvent(int id, Vector pos, int area) { - this.id = id; - this.pos = pos; - this.area = area; - } - - public String getTypeId() { - return "p"; - } - - public String[] getParameters() { - return new String[] { - String.valueOf(id), - String.valueOf(pos.getBlockX()), - String.valueOf(pos.getBlockY()), - String.valueOf(pos.getBlockZ()), - String.valueOf(area) - }; - } - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.cui; + +import com.sk89q.worldedit.Vector; + +public class SelectionPointEvent implements CUIEvent { + + protected final int id; + protected final Vector pos; + protected final int area; + + public SelectionPointEvent(int id, Vector pos, int area) { + this.id = id; + this.pos = pos; + this.area = area; + } + + public String getTypeId() { + return "p"; + } + + public String[] getParameters() { + return new String[] { + String.valueOf(id), + String.valueOf(pos.getBlockX()), + String.valueOf(pos.getBlockY()), + String.valueOf(pos.getBlockZ()), + String.valueOf(area) + }; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/cui/SelectionPolygonEvent.java b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionPolygonEvent.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/cui/SelectionPolygonEvent.java rename to src/main/java/com/sk89q/worldedit/internal/cui/SelectionPolygonEvent.java index cea73b392..3655be75d 100644 --- a/src/main/java/com/sk89q/worldedit/cui/SelectionPolygonEvent.java +++ b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionPolygonEvent.java @@ -1,42 +1,42 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.cui; - -public class SelectionPolygonEvent implements CUIEvent { - protected final int[] vertices; - - public SelectionPolygonEvent(int... vertices) { - this.vertices = vertices; - } - - public String getTypeId() { - return "poly"; - } - - public String[] getParameters() { - final String[] ret = new String[vertices.length]; - - int i = 0; - for (int vertex : vertices) { - ret[i++] = String.valueOf(vertex); - } - - return ret; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.cui; + +public class SelectionPolygonEvent implements CUIEvent { + protected final int[] vertices; + + public SelectionPolygonEvent(int... vertices) { + this.vertices = vertices; + } + + public String getTypeId() { + return "poly"; + } + + public String[] getParameters() { + final String[] ret = new String[vertices.length]; + + int i = 0; + for (int vertex : vertices) { + ret[i++] = String.valueOf(vertex); + } + + return ret; + } +} diff --git a/src/main/java/com/sk89q/worldedit/cui/SelectionShapeEvent.java b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionShapeEvent.java similarity index 93% rename from src/main/java/com/sk89q/worldedit/cui/SelectionShapeEvent.java rename to src/main/java/com/sk89q/worldedit/internal/cui/SelectionShapeEvent.java index f37175cda..715bbd273 100644 --- a/src/main/java/com/sk89q/worldedit/cui/SelectionShapeEvent.java +++ b/src/main/java/com/sk89q/worldedit/internal/cui/SelectionShapeEvent.java @@ -1,38 +1,38 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.cui; - -public class SelectionShapeEvent implements CUIEvent { - - protected final String shapeName; - - public SelectionShapeEvent(String shapeName) { - this.shapeName = shapeName; - } - - public String getTypeId() { - return "s"; - } - - public String[] getParameters() { - return new String[] { shapeName }; - } - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.cui; + +public class SelectionShapeEvent implements CUIEvent { + + protected final String shapeName; + + public SelectionShapeEvent(String shapeName) { + this.shapeName = shapeName; + } + + public String getTypeId() { + return "s"; + } + + public String[] getParameters() { + return new String[] { shapeName }; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/expression/Expression.java b/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java similarity index 86% rename from src/main/java/com/sk89q/worldedit/expression/Expression.java rename to src/main/java/com/sk89q/worldedit/internal/expression/Expression.java index f78ab76b3..a26051672 100644 --- a/src/main/java/com/sk89q/worldedit/expression/Expression.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java @@ -1,172 +1,170 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Stack; - -import com.sk89q.worldedit.BlockVector; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.expression.lexer.Lexer; -import com.sk89q.worldedit.expression.lexer.tokens.Token; -import com.sk89q.worldedit.expression.parser.Parser; -import com.sk89q.worldedit.expression.runtime.ExpressionEnvironment; -import com.sk89q.worldedit.expression.runtime.Constant; -import com.sk89q.worldedit.expression.runtime.EvaluationException; -import com.sk89q.worldedit.expression.runtime.Functions; -import com.sk89q.worldedit.expression.runtime.RValue; -import com.sk89q.worldedit.expression.runtime.ReturnException; -import com.sk89q.worldedit.expression.runtime.Variable; - -/** - * Compiles and evaluates expressions. - * - * Supported operators: - * Logical: &&, ||, ! (unary) - * Bitwise: ~ (unary), >>, << - * Arithmetic: +, -, *, /, % (modulo), ^ (power), - (unary), --, ++ (prefix only) - * Comparison: <=, >=, >, <, ==, !=, ~= (near) - * - * Supported functions: abs, acos, asin, atan, atan2, cbrt, ceil, cos, cosh, exp, floor, ln, log, log10, max, max, min, min, rint, round, sin, sinh, sqrt, tan, tanh and more. (See the Functions class or the wiki) - * - * Constants: e, pi - * - * To compile an equation, run Expression.compile("expression here", "var1", "var2"...) - * If you wish to run the equation multiple times, you can then optimize it, by calling myExpression.optimize(); - * You can then run the equation as many times as you want by calling myExpression.evaluate(var1, var2...) - * You do not need to pass values for all variables specified while compiling. - * To query variables after evaluation, you can use myExpression.getVariable("variable name"). - * To get a value out of these, use myVariable.getValue() - * - * Variables are also supported and can be set either by passing values to evaluate - * - * @author TomyLobo - */ -public class Expression { - private static final ThreadLocal> instance = new ThreadLocal>(); - - private final Map variables = new HashMap(); - private final String[] variableNames; - private RValue root; - private final Functions functions = new Functions(); - private ExpressionEnvironment environment; - - public static Expression compile(String expression, String... variableNames) throws ExpressionException { - return new Expression(expression, variableNames); - } - - private Expression(String expression, String... variableNames) throws ExpressionException { - this(Lexer.tokenize(expression), variableNames); - } - - private Expression(List tokens, String... variableNames) throws ExpressionException { - this.variableNames = variableNames; - - variables.put("e", new Constant(-1, Math.E)); - variables.put("pi", new Constant(-1, Math.PI)); - variables.put("true", new Constant(-1, 1)); - variables.put("false", new Constant(-1, 0)); - - for (String variableName : variableNames) { - if (variables.containsKey(variableName)) { - throw new ExpressionException(-1, "Tried to overwrite identifier '" + variableName + "'"); - } - variables.put(variableName, new Variable(0)); - } - - root = Parser.parse(tokens, this); - } - - public double evaluate(double... values) throws EvaluationException { - for (int i = 0; i < values.length; ++i) { - final String variableName = variableNames[i]; - final RValue invokable = variables.get(variableName); - if (!(invokable instanceof Variable)) { - throw new EvaluationException(invokable.getPosition(), "Tried to assign constant " + variableName + "."); - } - - ((Variable) invokable).value = values[i]; - } - - pushInstance(); - try { - return root.getValue(); - } catch (ReturnException e) { - return e.getValue(); - } finally { - popInstance(); - } - } - - public void optimize() throws EvaluationException { - root = root.optimize(); - } - - @Override - public String toString() { - return root.toString(); - } - - public RValue getVariable(String name, boolean create) { - RValue variable = variables.get(name); - if (variable == null && create) { - variables.put(name, variable = new Variable(0)); - } - - return variable; - } - - public static Expression getInstance() { - return instance.get().peek(); - } - - private void pushInstance() { - Stack foo = instance.get(); - if (foo == null) { - instance.set(foo = new Stack()); - } - - foo.push(this); - } - - private void popInstance() { - Stack foo = instance.get(); - - foo.pop(); - - if (foo.isEmpty()) { - instance.set(null); - } - } - - public Functions getFunctions() { - return functions; - } - - public ExpressionEnvironment getEnvironment() { - return environment; - } - - public void setEnvironment(ExpressionEnvironment environment) { - this.environment = environment; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +import com.sk89q.worldedit.internal.expression.lexer.Lexer; +import com.sk89q.worldedit.internal.expression.lexer.tokens.Token; +import com.sk89q.worldedit.internal.expression.parser.Parser; +import com.sk89q.worldedit.internal.expression.runtime.ExpressionEnvironment; +import com.sk89q.worldedit.internal.expression.runtime.Constant; +import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; +import com.sk89q.worldedit.internal.expression.runtime.Functions; +import com.sk89q.worldedit.internal.expression.runtime.RValue; +import com.sk89q.worldedit.internal.expression.runtime.ReturnException; +import com.sk89q.worldedit.internal.expression.runtime.Variable; + +/** + * Compiles and evaluates expressions. + * + * Supported operators: + * Logical: &&, ||, ! (unary) + * Bitwise: ~ (unary), >>, << + * Arithmetic: +, -, *, /, % (modulo), ^ (power), - (unary), --, ++ (prefix only) + * Comparison: <=, >=, >, <, ==, !=, ~= (near) + * + * Supported functions: abs, acos, asin, atan, atan2, cbrt, ceil, cos, cosh, exp, floor, ln, log, log10, max, max, min, min, rint, round, sin, sinh, sqrt, tan, tanh and more. (See the Functions class or the wiki) + * + * Constants: e, pi + * + * To compile an equation, run Expression.compile("expression here", "var1", "var2"...) + * If you wish to run the equation multiple times, you can then optimize it, by calling myExpression.optimize(); + * You can then run the equation as many times as you want by calling myExpression.evaluate(var1, var2...) + * You do not need to pass values for all variables specified while compiling. + * To query variables after evaluation, you can use myExpression.getVariable("variable name"). + * To get a value out of these, use myVariable.getValue() + * + * Variables are also supported and can be set either by passing values to evaluate + * + * @author TomyLobo + */ +public class Expression { + private static final ThreadLocal> instance = new ThreadLocal>(); + + private final Map variables = new HashMap(); + private final String[] variableNames; + private RValue root; + private final Functions functions = new Functions(); + private ExpressionEnvironment environment; + + public static Expression compile(String expression, String... variableNames) throws ExpressionException { + return new Expression(expression, variableNames); + } + + private Expression(String expression, String... variableNames) throws ExpressionException { + this(Lexer.tokenize(expression), variableNames); + } + + private Expression(List tokens, String... variableNames) throws ExpressionException { + this.variableNames = variableNames; + + variables.put("e", new Constant(-1, Math.E)); + variables.put("pi", new Constant(-1, Math.PI)); + variables.put("true", new Constant(-1, 1)); + variables.put("false", new Constant(-1, 0)); + + for (String variableName : variableNames) { + if (variables.containsKey(variableName)) { + throw new ExpressionException(-1, "Tried to overwrite identifier '" + variableName + "'"); + } + variables.put(variableName, new Variable(0)); + } + + root = Parser.parse(tokens, this); + } + + public double evaluate(double... values) throws EvaluationException { + for (int i = 0; i < values.length; ++i) { + final String variableName = variableNames[i]; + final RValue invokable = variables.get(variableName); + if (!(invokable instanceof Variable)) { + throw new EvaluationException(invokable.getPosition(), "Tried to assign constant " + variableName + "."); + } + + ((Variable) invokable).value = values[i]; + } + + pushInstance(); + try { + return root.getValue(); + } catch (ReturnException e) { + return e.getValue(); + } finally { + popInstance(); + } + } + + public void optimize() throws EvaluationException { + root = root.optimize(); + } + + @Override + public String toString() { + return root.toString(); + } + + public RValue getVariable(String name, boolean create) { + RValue variable = variables.get(name); + if (variable == null && create) { + variables.put(name, variable = new Variable(0)); + } + + return variable; + } + + public static Expression getInstance() { + return instance.get().peek(); + } + + private void pushInstance() { + Stack foo = instance.get(); + if (foo == null) { + instance.set(foo = new Stack()); + } + + foo.push(this); + } + + private void popInstance() { + Stack foo = instance.get(); + + foo.pop(); + + if (foo.isEmpty()) { + instance.set(null); + } + } + + public Functions getFunctions() { + return functions; + } + + public ExpressionEnvironment getEnvironment() { + return environment; + } + + public void setEnvironment(ExpressionEnvironment environment) { + this.environment = environment; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/ExpressionException.java b/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionException.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/expression/ExpressionException.java rename to src/main/java/com/sk89q/worldedit/internal/expression/ExpressionException.java index 6bd1597ac..4188dfdab 100644 --- a/src/main/java/com/sk89q/worldedit/expression/ExpressionException.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionException.java @@ -1,54 +1,54 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression; - -/** - * Thrown when there's a problem during any stage of the expression compilation or evaluation. - * - * @author TomyLobo - */ -public class ExpressionException extends Exception { - private static final long serialVersionUID = 1L; - - private final int position; - - public ExpressionException(int position) { - this.position = position; - } - - public ExpressionException(int position, String message, Throwable cause) { - super(message, cause); - this.position = position; - } - - public ExpressionException(int position, String message) { - super(message); - this.position = position; - } - - public ExpressionException(int position, Throwable cause) { - super(cause); - this.position = position; - } - - public int getPosition() { - return position; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression; + +/** + * Thrown when there's a problem during any stage of the expression compilation or evaluation. + * + * @author TomyLobo + */ +public class ExpressionException extends Exception { + private static final long serialVersionUID = 1L; + + private final int position; + + public ExpressionException(int position) { + this.position = position; + } + + public ExpressionException(int position, String message, Throwable cause) { + super(message, cause); + this.position = position; + } + + public ExpressionException(int position, String message) { + super(message); + this.position = position; + } + + public ExpressionException(int position, Throwable cause) { + super(cause); + this.position = position; + } + + public int getPosition() { + return position; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/Identifiable.java b/src/main/java/com/sk89q/worldedit/internal/expression/Identifiable.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/expression/Identifiable.java rename to src/main/java/com/sk89q/worldedit/internal/expression/Identifiable.java index 5ce398a27..17086c325 100644 --- a/src/main/java/com/sk89q/worldedit/expression/Identifiable.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/Identifiable.java @@ -1,61 +1,61 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression; - -/** - * A common superinterface for everything passed to parser processors. - * - * @author TomyLobo - */ -public interface Identifiable { - /** - * Returns a character that helps identify the token, pseudo-token or invokable in question. - * - *
-     * Tokens:
-     * i - IdentifierToken
-     * 0 - NumberToken
-     * o - OperatorToken
-     * \0 - NullToken
-     * CharacterTokens are returned literally
-     *
-     * PseudoTokens:
-     * p - UnaryOperator
-     * V - UnboundVariable
-     *
-     * Nodes:
-     * c - Constant
-     * v - Variable
-     * f - Function
-     * l - LValueFunction
-     * s - Sequence
-     * I - Conditional
-     * w - While
-     * F - For
-     * r - Return
-     * b - Break (includes continue)
-     * S - SimpleFor
-     * C - Switch
-     * 
- */ - public abstract char id(); - - public int getPosition(); -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression; + +/** + * A common superinterface for everything passed to parser processors. + * + * @author TomyLobo + */ +public interface Identifiable { + /** + * Returns a character that helps identify the token, pseudo-token or invokable in question. + * + *
+     * Tokens:
+     * i - IdentifierToken
+     * 0 - NumberToken
+     * o - OperatorToken
+     * \0 - NullToken
+     * CharacterTokens are returned literally
+     *
+     * PseudoTokens:
+     * p - UnaryOperator
+     * V - UnboundVariable
+     *
+     * Nodes:
+     * c - Constant
+     * v - Variable
+     * f - Function
+     * l - LValueFunction
+     * s - Sequence
+     * I - Conditional
+     * w - While
+     * F - For
+     * r - Return
+     * b - Break (includes continue)
+     * S - SimpleFor
+     * C - Switch
+     * 
+ */ + public abstract char id(); + + public int getPosition(); +} diff --git a/src/main/java/com/sk89q/worldedit/expression/lexer/Lexer.java b/src/main/java/com/sk89q/worldedit/internal/expression/lexer/Lexer.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/expression/lexer/Lexer.java rename to src/main/java/com/sk89q/worldedit/internal/expression/lexer/Lexer.java index bfce6fb0a..bcced9640 100644 --- a/src/main/java/com/sk89q/worldedit/expression/lexer/Lexer.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/lexer/Lexer.java @@ -1,233 +1,233 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.lexer; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import com.sk89q.worldedit.expression.lexer.tokens.*; - -/** - * Processes a string into a list of tokens. - * - * Tokens can be numbers, identifiers, operators and assorted other characters. - * - * @author TomyLobo - */ -public class Lexer { - private final String expression; - private int position = 0; - - private Lexer(String expression) { - this.expression = expression; - } - - public static final List tokenize(String expression) throws LexerException { - return new Lexer(expression).tokenize(); - } - - private final DecisionTree operatorTree = new DecisionTree(null, - '+', new DecisionTree("+", - '=', new DecisionTree("+="), - '+', new DecisionTree("++") - ), - '-', new DecisionTree("-", - '=', new DecisionTree("-="), - '-', new DecisionTree("--") - ), - '*', new DecisionTree("*", - '=', new DecisionTree("*="), - '*', new DecisionTree("**") - ), - '/', new DecisionTree("/", - '=', new DecisionTree("/=") - ), - '%', new DecisionTree("%", - '=', new DecisionTree("%=") - ), - '^', new DecisionTree("^", - '=', new DecisionTree("^=") - ), - '=', new DecisionTree("=", - '=', new DecisionTree("==") - ), - '!', new DecisionTree("!", - '=', new DecisionTree("!=") - ), - '<', new DecisionTree("<", - '<', new DecisionTree("<<"), - '=', new DecisionTree("<=") - ), - '>', new DecisionTree(">", - '>', new DecisionTree(">>"), - '=', new DecisionTree(">=") - ), - '&', new DecisionTree(null, // not implemented - '&', new DecisionTree("&&") - ), - '|', new DecisionTree(null, // not implemented - '|', new DecisionTree("||") - ), - '~', new DecisionTree("~", - '=', new DecisionTree("~=") - ) - ); - - private static final Set characterTokens = new HashSet(); - static { - characterTokens.add(','); - characterTokens.add('('); - characterTokens.add(')'); - characterTokens.add('{'); - characterTokens.add('}'); - characterTokens.add(';'); - characterTokens.add('?'); - characterTokens.add(':'); - } - - private static final Set keywords = new HashSet(Arrays.asList("if", "else", "while", "do", "for", "break", "continue", "return", "switch", "case", "default")); - - private static final Pattern numberPattern = Pattern.compile("^([0-9]*(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?)"); - private static final Pattern identifierPattern = Pattern.compile("^([A-Za-z][0-9A-Za-z_]*)"); - - private final List tokenize() throws LexerException { - List tokens = new ArrayList(); - - do { - skipWhitespace(); - if (position >= expression.length()) { - break; - } - - Token token = operatorTree.evaluate(position); - if (token != null) { - tokens.add(token); - continue; - } - - final char ch = peek(); - - if (characterTokens.contains(ch)) { - tokens.add(new CharacterToken(position++, ch)); - continue; - } - - final Matcher numberMatcher = numberPattern.matcher(expression.substring(position)); - if (numberMatcher.lookingAt()) { - String numberPart = numberMatcher.group(1); - if (numberPart.length() > 0) { - try { - tokens.add(new NumberToken(position, Double.parseDouble(numberPart))); - } catch (NumberFormatException e) { - throw new LexerException(position, "Number parsing failed", e); - } - - position += numberPart.length(); - continue; - } - } - - final Matcher identifierMatcher = identifierPattern.matcher(expression.substring(position)); - if (identifierMatcher.lookingAt()) { - String identifierPart = identifierMatcher.group(1); - if (identifierPart.length() > 0) { - if (keywords.contains(identifierPart)) { - tokens.add(new KeywordToken(position, identifierPart)); - } else { - tokens.add(new IdentifierToken(position, identifierPart)); - } - - position += identifierPart.length(); - continue; - } - } - - throw new LexerException(position, "Unknown character '" + ch + "'"); - } while (position < expression.length()); - - return tokens; - } - - private char peek() { - return expression.charAt(position); - } - - private final void skipWhitespace() { - while (position < expression.length() && Character.isWhitespace(peek())) { - ++position; - } - } - - public class DecisionTree { - private final String tokenName; - private final Map subTrees = new HashMap(); - - private DecisionTree(String tokenName, Object... args) { - this.tokenName = tokenName; - - if (args.length % 2 != 0) { - throw new UnsupportedOperationException("You need to pass an even number of arguments."); - } - - for (int i = 0; i < args.length; i += 2) { - if (!(args[i] instanceof Character)) { - throw new UnsupportedOperationException("Argument #" + i + " expected to be 'Character', not '" + args[i].getClass().getName() + "'."); - } - if (!(args[i + 1] instanceof DecisionTree)) { - throw new UnsupportedOperationException("Argument #" + (i + 1) + " expected to be 'DecisionTree', not '" + args[i + 1].getClass().getName() + "'."); - } - - Character next = (Character) args[i]; - DecisionTree subTree = (DecisionTree) args[i + 1]; - - subTrees.put(next, subTree); - } - } - - private Token evaluate(int startPosition) throws LexerException { - if (position < expression.length()) { - final char next = peek(); - - final DecisionTree subTree = subTrees.get(next); - if (subTree != null) { - ++position; - final Token subTreeResult = subTree.evaluate(startPosition); - if (subTreeResult != null) { - return subTreeResult; - } - --position; - } - } - - if (tokenName == null) { - return null; - } - - return new OperatorToken(startPosition, tokenName); - } - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.lexer; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.sk89q.worldedit.internal.expression.lexer.tokens.*; + +/** + * Processes a string into a list of tokens. + * + * Tokens can be numbers, identifiers, operators and assorted other characters. + * + * @author TomyLobo + */ +public class Lexer { + private final String expression; + private int position = 0; + + private Lexer(String expression) { + this.expression = expression; + } + + public static final List tokenize(String expression) throws LexerException { + return new Lexer(expression).tokenize(); + } + + private final DecisionTree operatorTree = new DecisionTree(null, + '+', new DecisionTree("+", + '=', new DecisionTree("+="), + '+', new DecisionTree("++") + ), + '-', new DecisionTree("-", + '=', new DecisionTree("-="), + '-', new DecisionTree("--") + ), + '*', new DecisionTree("*", + '=', new DecisionTree("*="), + '*', new DecisionTree("**") + ), + '/', new DecisionTree("/", + '=', new DecisionTree("/=") + ), + '%', new DecisionTree("%", + '=', new DecisionTree("%=") + ), + '^', new DecisionTree("^", + '=', new DecisionTree("^=") + ), + '=', new DecisionTree("=", + '=', new DecisionTree("==") + ), + '!', new DecisionTree("!", + '=', new DecisionTree("!=") + ), + '<', new DecisionTree("<", + '<', new DecisionTree("<<"), + '=', new DecisionTree("<=") + ), + '>', new DecisionTree(">", + '>', new DecisionTree(">>"), + '=', new DecisionTree(">=") + ), + '&', new DecisionTree(null, // not implemented + '&', new DecisionTree("&&") + ), + '|', new DecisionTree(null, // not implemented + '|', new DecisionTree("||") + ), + '~', new DecisionTree("~", + '=', new DecisionTree("~=") + ) + ); + + private static final Set characterTokens = new HashSet(); + static { + characterTokens.add(','); + characterTokens.add('('); + characterTokens.add(')'); + characterTokens.add('{'); + characterTokens.add('}'); + characterTokens.add(';'); + characterTokens.add('?'); + characterTokens.add(':'); + } + + private static final Set keywords = new HashSet(Arrays.asList("if", "else", "while", "do", "for", "break", "continue", "return", "switch", "case", "default")); + + private static final Pattern numberPattern = Pattern.compile("^([0-9]*(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?)"); + private static final Pattern identifierPattern = Pattern.compile("^([A-Za-z][0-9A-Za-z_]*)"); + + private final List tokenize() throws LexerException { + List tokens = new ArrayList(); + + do { + skipWhitespace(); + if (position >= expression.length()) { + break; + } + + Token token = operatorTree.evaluate(position); + if (token != null) { + tokens.add(token); + continue; + } + + final char ch = peek(); + + if (characterTokens.contains(ch)) { + tokens.add(new CharacterToken(position++, ch)); + continue; + } + + final Matcher numberMatcher = numberPattern.matcher(expression.substring(position)); + if (numberMatcher.lookingAt()) { + String numberPart = numberMatcher.group(1); + if (numberPart.length() > 0) { + try { + tokens.add(new NumberToken(position, Double.parseDouble(numberPart))); + } catch (NumberFormatException e) { + throw new LexerException(position, "Number parsing failed", e); + } + + position += numberPart.length(); + continue; + } + } + + final Matcher identifierMatcher = identifierPattern.matcher(expression.substring(position)); + if (identifierMatcher.lookingAt()) { + String identifierPart = identifierMatcher.group(1); + if (identifierPart.length() > 0) { + if (keywords.contains(identifierPart)) { + tokens.add(new KeywordToken(position, identifierPart)); + } else { + tokens.add(new IdentifierToken(position, identifierPart)); + } + + position += identifierPart.length(); + continue; + } + } + + throw new LexerException(position, "Unknown character '" + ch + "'"); + } while (position < expression.length()); + + return tokens; + } + + private char peek() { + return expression.charAt(position); + } + + private final void skipWhitespace() { + while (position < expression.length() && Character.isWhitespace(peek())) { + ++position; + } + } + + public class DecisionTree { + private final String tokenName; + private final Map subTrees = new HashMap(); + + private DecisionTree(String tokenName, Object... args) { + this.tokenName = tokenName; + + if (args.length % 2 != 0) { + throw new UnsupportedOperationException("You need to pass an even number of arguments."); + } + + for (int i = 0; i < args.length; i += 2) { + if (!(args[i] instanceof Character)) { + throw new UnsupportedOperationException("Argument #" + i + " expected to be 'Character', not '" + args[i].getClass().getName() + "'."); + } + if (!(args[i + 1] instanceof DecisionTree)) { + throw new UnsupportedOperationException("Argument #" + (i + 1) + " expected to be 'DecisionTree', not '" + args[i + 1].getClass().getName() + "'."); + } + + Character next = (Character) args[i]; + DecisionTree subTree = (DecisionTree) args[i + 1]; + + subTrees.put(next, subTree); + } + } + + private Token evaluate(int startPosition) throws LexerException { + if (position < expression.length()) { + final char next = peek(); + + final DecisionTree subTree = subTrees.get(next); + if (subTree != null) { + ++position; + final Token subTreeResult = subTree.evaluate(startPosition); + if (subTreeResult != null) { + return subTreeResult; + } + --position; + } + } + + if (tokenName == null) { + return null; + } + + return new OperatorToken(startPosition, tokenName); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/lexer/LexerException.java b/src/main/java/com/sk89q/worldedit/internal/expression/lexer/LexerException.java similarity index 91% rename from src/main/java/com/sk89q/worldedit/expression/lexer/LexerException.java rename to src/main/java/com/sk89q/worldedit/internal/expression/lexer/LexerException.java index c854b8360..292eac5de 100644 --- a/src/main/java/com/sk89q/worldedit/expression/lexer/LexerException.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/lexer/LexerException.java @@ -1,51 +1,51 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.lexer; - -import com.sk89q.worldedit.expression.ExpressionException; - -/** - * Thrown when the lexer encounters a problem. - * - * @author TomyLobo - */ -public class LexerException extends ExpressionException { - private static final long serialVersionUID = 1L; - - public LexerException(int position) { - super(position, getPrefix(position)); - } - - public LexerException(int position, String message, Throwable cause) { - super(position, getPrefix(position) + ": " + message, cause); - } - - public LexerException(int position, String message) { - super(position, getPrefix(position) + ": " + message); - } - - public LexerException(int position, Throwable cause) { - super(position, getPrefix(position), cause); - } - - private static String getPrefix(int position) { - return position < 0 ? "Lexer error" : ("Lexer error at " + (position + 1)); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.lexer; + +import com.sk89q.worldedit.internal.expression.ExpressionException; + +/** + * Thrown when the lexer encounters a problem. + * + * @author TomyLobo + */ +public class LexerException extends ExpressionException { + private static final long serialVersionUID = 1L; + + public LexerException(int position) { + super(position, getPrefix(position)); + } + + public LexerException(int position, String message, Throwable cause) { + super(position, getPrefix(position) + ": " + message, cause); + } + + public LexerException(int position, String message) { + super(position, getPrefix(position) + ": " + message); + } + + public LexerException(int position, Throwable cause) { + super(position, getPrefix(position), cause); + } + + private static String getPrefix(int position) { + return position < 0 ? "Lexer error" : ("Lexer error at " + (position + 1)); + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/lexer/tokens/CharacterToken.java b/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/CharacterToken.java similarity index 92% rename from src/main/java/com/sk89q/worldedit/expression/lexer/tokens/CharacterToken.java rename to src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/CharacterToken.java index 1757ae2b5..fc399db83 100644 --- a/src/main/java/com/sk89q/worldedit/expression/lexer/tokens/CharacterToken.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/CharacterToken.java @@ -1,44 +1,44 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.lexer.tokens; - -/** - * A single character that doesn't fit any of the other token categories. - * - * @author TomyLobo - */ -public class CharacterToken extends Token { - public final char character; - - public CharacterToken(int position, char character) { - super(position); - this.character = character; - } - - @Override - public char id() { - return character; - } - - @Override - public String toString() { - return "CharacterToken(" + character + ")"; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.lexer.tokens; + +/** + * A single character that doesn't fit any of the other token categories. + * + * @author TomyLobo + */ +public class CharacterToken extends Token { + public final char character; + + public CharacterToken(int position, char character) { + super(position); + this.character = character; + } + + @Override + public char id() { + return character; + } + + @Override + public String toString() { + return "CharacterToken(" + character + ")"; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/lexer/tokens/IdentifierToken.java b/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/IdentifierToken.java similarity index 92% rename from src/main/java/com/sk89q/worldedit/expression/lexer/tokens/IdentifierToken.java rename to src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/IdentifierToken.java index b4dab7f11..352ceb168 100644 --- a/src/main/java/com/sk89q/worldedit/expression/lexer/tokens/IdentifierToken.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/IdentifierToken.java @@ -1,44 +1,44 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.lexer.tokens; - -/** - * An identifier - * - * @author TomyLobo - */ -public class IdentifierToken extends Token { - public final String value; - - public IdentifierToken(int position, String value) { - super(position); - this.value = value; - } - - @Override - public char id() { - return 'i'; - } - - @Override - public String toString() { - return "IdentifierToken(" + value + ")"; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.lexer.tokens; + +/** + * An identifier + * + * @author TomyLobo + */ +public class IdentifierToken extends Token { + public final String value; + + public IdentifierToken(int position, String value) { + super(position); + this.value = value; + } + + @Override + public char id() { + return 'i'; + } + + @Override + public String toString() { + return "IdentifierToken(" + value + ")"; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/lexer/tokens/KeywordToken.java b/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/KeywordToken.java similarity index 92% rename from src/main/java/com/sk89q/worldedit/expression/lexer/tokens/KeywordToken.java rename to src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/KeywordToken.java index d2f7c755b..bdbe706c9 100644 --- a/src/main/java/com/sk89q/worldedit/expression/lexer/tokens/KeywordToken.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/KeywordToken.java @@ -1,44 +1,44 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.lexer.tokens; - -/** - * A keyword - * - * @author TomyLobo - */ -public class KeywordToken extends Token { - public final String value; - - public KeywordToken(int position, String value) { - super(position); - this.value = value; - } - - @Override - public char id() { - return 'k'; - } - - @Override - public String toString() { - return "KeywordToken(" + value + ")"; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.lexer.tokens; + +/** + * A keyword + * + * @author TomyLobo + */ +public class KeywordToken extends Token { + public final String value; + + public KeywordToken(int position, String value) { + super(position); + this.value = value; + } + + @Override + public char id() { + return 'k'; + } + + @Override + public String toString() { + return "KeywordToken(" + value + ")"; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/lexer/tokens/NumberToken.java b/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/NumberToken.java similarity index 92% rename from src/main/java/com/sk89q/worldedit/expression/lexer/tokens/NumberToken.java rename to src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/NumberToken.java index 77ebaa743..f4176748e 100644 --- a/src/main/java/com/sk89q/worldedit/expression/lexer/tokens/NumberToken.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/NumberToken.java @@ -1,44 +1,44 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.lexer.tokens; - -/** - * A number - * - * @author TomyLobo - */ -public class NumberToken extends Token { - public final double value; - - public NumberToken(int position, double value) { - super(position); - this.value = value; - } - - @Override - public char id() { - return '0'; - } - - @Override - public String toString() { - return "NumberToken(" + value + ")"; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.lexer.tokens; + +/** + * A number + * + * @author TomyLobo + */ +public class NumberToken extends Token { + public final double value; + + public NumberToken(int position, double value) { + super(position); + this.value = value; + } + + @Override + public char id() { + return '0'; + } + + @Override + public String toString() { + return "NumberToken(" + value + ")"; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/lexer/tokens/OperatorToken.java b/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/OperatorToken.java similarity index 92% rename from src/main/java/com/sk89q/worldedit/expression/lexer/tokens/OperatorToken.java rename to src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/OperatorToken.java index 169fc0d7a..d1aa1c71a 100644 --- a/src/main/java/com/sk89q/worldedit/expression/lexer/tokens/OperatorToken.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/OperatorToken.java @@ -1,44 +1,44 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.lexer.tokens; - -/** - * A unary or binary operator. - * - * @author TomyLobo - */ -public class OperatorToken extends Token { - public final String operator; - - public OperatorToken(int position, String operator) { - super(position); - this.operator = operator; - } - - @Override - public char id() { - return 'o'; - } - - @Override - public String toString() { - return "OperatorToken(" + operator + ")"; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.lexer.tokens; + +/** + * A unary or binary operator. + * + * @author TomyLobo + */ +public class OperatorToken extends Token { + public final String operator; + + public OperatorToken(int position, String operator) { + super(position); + this.operator = operator; + } + + @Override + public char id() { + return 'o'; + } + + @Override + public String toString() { + return "OperatorToken(" + operator + ")"; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/lexer/tokens/Token.java b/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/Token.java similarity index 88% rename from src/main/java/com/sk89q/worldedit/expression/lexer/tokens/Token.java rename to src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/Token.java index 80e199884..83da0953b 100644 --- a/src/main/java/com/sk89q/worldedit/expression/lexer/tokens/Token.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/Token.java @@ -1,40 +1,40 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.lexer.tokens; - -import com.sk89q.worldedit.expression.Identifiable; - -/** - * A token. The lexer generates these to make the parser's job easier. - * - * @author TomyLobo - */ -public abstract class Token implements Identifiable { - private final int position; - - public Token(int position) { - this.position = position; - } - - @Override - public int getPosition() { - return position; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.lexer.tokens; + +import com.sk89q.worldedit.internal.expression.Identifiable; + +/** + * A token. The lexer generates these to make the parser's job easier. + * + * @author TomyLobo + */ +public abstract class Token implements Identifiable { + private final int position; + + public Token(int position) { + this.position = position; + } + + @Override + public int getPosition() { + return position; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/parser/Parser.java b/src/main/java/com/sk89q/worldedit/internal/expression/parser/Parser.java similarity index 90% rename from src/main/java/com/sk89q/worldedit/expression/parser/Parser.java rename to src/main/java/com/sk89q/worldedit/internal/expression/parser/Parser.java index 9ebb71a0d..fbb425155 100644 --- a/src/main/java/com/sk89q/worldedit/expression/parser/Parser.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/parser/Parser.java @@ -1,466 +1,466 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.parser; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import com.sk89q.worldedit.expression.Expression; -import com.sk89q.worldedit.expression.Identifiable; -import com.sk89q.worldedit.expression.lexer.tokens.IdentifierToken; -import com.sk89q.worldedit.expression.lexer.tokens.KeywordToken; -import com.sk89q.worldedit.expression.lexer.tokens.NumberToken; -import com.sk89q.worldedit.expression.lexer.tokens.OperatorToken; -import com.sk89q.worldedit.expression.lexer.tokens.Token; -import com.sk89q.worldedit.expression.runtime.Break; -import com.sk89q.worldedit.expression.runtime.Conditional; -import com.sk89q.worldedit.expression.runtime.Constant; -import com.sk89q.worldedit.expression.runtime.For; -import com.sk89q.worldedit.expression.runtime.Function; -import com.sk89q.worldedit.expression.runtime.Functions; -import com.sk89q.worldedit.expression.runtime.LValue; -import com.sk89q.worldedit.expression.runtime.RValue; -import com.sk89q.worldedit.expression.runtime.Return; -import com.sk89q.worldedit.expression.runtime.Sequence; -import com.sk89q.worldedit.expression.runtime.SimpleFor; -import com.sk89q.worldedit.expression.runtime.Switch; -import com.sk89q.worldedit.expression.runtime.While; - -/** - * Processes a list of tokens into an executable tree. - * - * Tokens can be numbers, identifiers, operators and assorted other characters. - * - * @author TomyLobo - */ -public class Parser { - private final class NullToken extends Token { - private NullToken(int position) { - super(position); - } - - public char id() { - return '\0'; - } - - @Override - public String toString() { - return "NullToken"; - } - } - - private final List tokens; - private int position = 0; - private Expression expression; - - private Parser(List tokens, Expression expression) { - this.tokens = tokens; - this.expression = expression; - } - - public static final RValue parse(List tokens, Expression expression) throws ParserException { - return new Parser(tokens, expression).parse(); - } - - private RValue parse() throws ParserException { - final RValue ret = parseStatements(false); - if (position < tokens.size()) { - final Token token = peek(); - throw new ParserException(token.getPosition(), "Extra token at the end of the input: " + token); - } - - ret.bindVariables(expression, false); - - return ret; - } - - private RValue parseStatements(boolean singleStatement) throws ParserException { - List statements = new ArrayList(); - loop: while (position < tokens.size()) { - boolean expectSemicolon = false; - - final Token current = peek(); - switch (current.id()) { - case '{': - consumeCharacter('{'); - - statements.add(parseStatements(false)); - - consumeCharacter('}'); - - break; - - case '}': - break loop; - - case 'k': - final String keyword = ((KeywordToken) current).value; - switch (keyword.charAt(0)) { - case 'i': { // if - ++position; - final RValue condition = parseBracket(); - final RValue truePart = parseStatements(true); - final RValue falsePart; - - if (hasKeyword("else")) { - ++position; - falsePart = parseStatements(true); - } else { - falsePart = null; - } - - statements.add(new Conditional(current.getPosition(), condition, truePart, falsePart)); - break; - } - - case 'w': { // while - ++position; - final RValue condition = parseBracket(); - final RValue body = parseStatements(true); - - statements.add(new While(current.getPosition(), condition, body, false)); - break; - } - - case 'd': { // do/default - if (hasKeyword("default")) { - break loop; - } - - ++position; - final RValue body = parseStatements(true); - - consumeKeyword("while"); - - final RValue condition = parseBracket(); - - statements.add(new While(current.getPosition(), condition, body, true)); - - expectSemicolon = true; - break; - } - - case 'f': { // for - ++position; - consumeCharacter('('); - int oldPosition = position; - final RValue init = parseExpression(true); - //if ((init instanceof LValue) && ) - if (peek().id() == ';') { - ++position; - final RValue condition = parseExpression(true); - consumeCharacter(';'); - final RValue increment = parseExpression(true); - consumeCharacter(')'); - final RValue body = parseStatements(true); - - statements.add(new For(current.getPosition(), init, condition, increment, body)); - } else { - position = oldPosition; - - final Token variableToken = peek(); - if (!(variableToken instanceof IdentifierToken)) { - throw new ParserException(variableToken.getPosition(), "Expected identifier"); - } - - RValue variable = expression.getVariable(((IdentifierToken) variableToken).value, true); - if (!(variable instanceof LValue)) { - throw new ParserException(variableToken.getPosition(), "Expected variable"); - } - ++position; - - final Token equalsToken = peek(); - if (!(equalsToken instanceof OperatorToken) || !((OperatorToken) equalsToken).operator.equals("=")) { - throw new ParserException(variableToken.getPosition(), "Expected '=' or a term and ';'"); - } - ++position; - - final RValue first = parseExpression(true); - consumeCharacter(','); - final RValue last = parseExpression(true); - consumeCharacter(')'); - final RValue body = parseStatements(true); - - statements.add(new SimpleFor(current.getPosition(), (LValue) variable, first, last, body)); - } // switch (keyword.charAt(0)) - break; - } - - case 'b': // break - ++position; - statements.add(new Break(current.getPosition(), false)); - break; - - case 'c': // continue/case - if (hasKeyword("case")) { - break loop; - } - - ++position; - statements.add(new Break(current.getPosition(), true)); - break; - - case 'r': // return - ++position; - statements.add(new Return(current.getPosition(), parseExpression(true))); - - expectSemicolon = true; - break; - - case 's': // switch - ++position; - final RValue parameter = parseBracket(); - final List values = new ArrayList(); - final List caseStatements = new ArrayList(); - RValue defaultCase = null; - - consumeCharacter('{'); - while (peek().id() != '}') { - if (position >= tokens.size()) { - throw new ParserException(current.getPosition(), "Expected '}' instead of EOF"); - } - if (defaultCase != null) { - throw new ParserException(current.getPosition(), "Expected '}' instead of " + peek()); - } - - if (hasKeyword("case")) { - ++position; - - final Token valueToken = peek(); - if (!(valueToken instanceof NumberToken)) { - throw new ParserException(current.getPosition(), "Expected number instead of " + peek()); - } - - ++position; - - values.add(((NumberToken) valueToken).value); - - consumeCharacter(':'); - caseStatements.add(parseStatements(false)); - } else if (hasKeyword("default")) { - ++position; - - consumeCharacter(':'); - defaultCase = parseStatements(false); - } else { - throw new ParserException(current.getPosition(), "Expected 'case' or 'default' instead of " + peek()); - } - } - consumeCharacter('}'); - - statements.add(new Switch(current.getPosition(), parameter, values, caseStatements, defaultCase)); - break; - - default: - throw new ParserException(current.getPosition(), "Unexpected keyword '" + keyword + "'"); - } - - break; - - default: - statements.add(parseExpression(true)); - - expectSemicolon = true; - } // switch (current.id()) - - if (expectSemicolon) { - if (peek().id() == ';') { - ++position; - } else { - break; - } - } - - if (singleStatement) { - break; - } - } // while (position < tokens.size()) - - switch (statements.size()) { - case 0: - if (singleStatement) { - throw new ParserException(peek().getPosition(), "Statement expected."); - } - - return new Sequence(peek().getPosition()); - - case 1: - return statements.get(0); - - default: - return new Sequence(peek().getPosition(), statements.toArray(new RValue[statements.size()])); - } - } - - private final RValue parseExpression(boolean canBeEmpty) throws ParserException { - LinkedList halfProcessed = new LinkedList(); - - // process brackets, numbers, functions, variables and detect prefix operators - boolean expressionStart = true; - loop: while (position < tokens.size()) { - final Token current = peek(); - - switch (current.id()) { - case '0': - halfProcessed.add(new Constant(current.getPosition(), ((NumberToken) current).value)); - ++position; - expressionStart = false; - break; - - case 'i': - final IdentifierToken identifierToken = (IdentifierToken) current; - ++position; - - final Token next = peek(); - if (next.id() == '(') { - halfProcessed.add(parseFunctionCall(identifierToken)); - } else { - final RValue variable = expression.getVariable(identifierToken.value, false); - if (variable == null) { - halfProcessed.add(new UnboundVariable(identifierToken.getPosition(), identifierToken.value)); - } else { - halfProcessed.add(variable); - } - } - expressionStart = false; - break; - - case '(': - halfProcessed.add(parseBracket()); - expressionStart = false; - break; - - case ',': - case ')': - case '}': - case ';': - break loop; - - case 'o': - if (expressionStart) { - // Preprocess prefix operators into unary operators - halfProcessed.add(new UnaryOperator((OperatorToken) current)); - } else { - halfProcessed.add(current); - } - ++position; - expressionStart = true; - break; - - default: - halfProcessed.add(current); - ++position; - expressionStart = false; - break; - } - } - - if (halfProcessed.isEmpty() && canBeEmpty) { - return new Sequence(peek().getPosition()); - } - - return ParserProcessors.processExpression(halfProcessed); - } - - - private Token peek() { - if (position >= tokens.size()) { - return new NullToken(tokens.get(tokens.size() - 1).getPosition() + 1); - } - - return tokens.get(position); - } - - private Function parseFunctionCall(IdentifierToken identifierToken) throws ParserException { - consumeCharacter('('); - - try { - if (peek().id() == ')') { - ++position; - return Functions.getFunction(identifierToken.getPosition(), identifierToken.value); - } - - List args = new ArrayList(); - - loop: while (true) { - args.add(parseExpression(false)); - - final Token current = peek(); - ++position; - - switch (current.id()) { - case ',': - continue; - - case ')': - break loop; - - default: - throw new ParserException(current.getPosition(), "Unmatched opening bracket"); - } - } - - return Functions.getFunction(identifierToken.getPosition(), identifierToken.value, args.toArray(new RValue[args.size()])); - } catch (NoSuchMethodException e) { - throw new ParserException(identifierToken.getPosition(), "Function '" + identifierToken.value + "' not found", e); - } - } - - private final RValue parseBracket() throws ParserException { - consumeCharacter('('); - - final RValue ret = parseExpression(false); - - consumeCharacter(')'); - - return ret; - } - - private boolean hasKeyword(String keyword) { - final Token next = peek(); - if (!(next instanceof KeywordToken)) { - return false; - } - return ((KeywordToken) next).value.equals(keyword); - } - - private void assertCharacter(char character) throws ParserException { - final Token next = peek(); - if (next.id() != character) { - throw new ParserException(next.getPosition(), "Expected '" + character + "'"); - } - } - - private void assertKeyword(String keyword) throws ParserException { - if (!hasKeyword(keyword)) { - throw new ParserException(peek().getPosition(), "Expected '" + keyword + "'"); - } - } - - private void consumeCharacter(char character) throws ParserException { - assertCharacter(character); - ++position; - } - - private void consumeKeyword(String keyword) throws ParserException { - assertKeyword(keyword); - ++position; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.parser; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.Identifiable; +import com.sk89q.worldedit.internal.expression.lexer.tokens.IdentifierToken; +import com.sk89q.worldedit.internal.expression.lexer.tokens.KeywordToken; +import com.sk89q.worldedit.internal.expression.lexer.tokens.NumberToken; +import com.sk89q.worldedit.internal.expression.lexer.tokens.OperatorToken; +import com.sk89q.worldedit.internal.expression.lexer.tokens.Token; +import com.sk89q.worldedit.internal.expression.runtime.Break; +import com.sk89q.worldedit.internal.expression.runtime.Conditional; +import com.sk89q.worldedit.internal.expression.runtime.Constant; +import com.sk89q.worldedit.internal.expression.runtime.For; +import com.sk89q.worldedit.internal.expression.runtime.Function; +import com.sk89q.worldedit.internal.expression.runtime.Functions; +import com.sk89q.worldedit.internal.expression.runtime.LValue; +import com.sk89q.worldedit.internal.expression.runtime.RValue; +import com.sk89q.worldedit.internal.expression.runtime.Return; +import com.sk89q.worldedit.internal.expression.runtime.Sequence; +import com.sk89q.worldedit.internal.expression.runtime.SimpleFor; +import com.sk89q.worldedit.internal.expression.runtime.Switch; +import com.sk89q.worldedit.internal.expression.runtime.While; + +/** + * Processes a list of tokens into an executable tree. + * + * Tokens can be numbers, identifiers, operators and assorted other characters. + * + * @author TomyLobo + */ +public class Parser { + private final class NullToken extends Token { + private NullToken(int position) { + super(position); + } + + public char id() { + return '\0'; + } + + @Override + public String toString() { + return "NullToken"; + } + } + + private final List tokens; + private int position = 0; + private Expression expression; + + private Parser(List tokens, Expression expression) { + this.tokens = tokens; + this.expression = expression; + } + + public static final RValue parse(List tokens, Expression expression) throws ParserException { + return new Parser(tokens, expression).parse(); + } + + private RValue parse() throws ParserException { + final RValue ret = parseStatements(false); + if (position < tokens.size()) { + final Token token = peek(); + throw new ParserException(token.getPosition(), "Extra token at the end of the input: " + token); + } + + ret.bindVariables(expression, false); + + return ret; + } + + private RValue parseStatements(boolean singleStatement) throws ParserException { + List statements = new ArrayList(); + loop: while (position < tokens.size()) { + boolean expectSemicolon = false; + + final Token current = peek(); + switch (current.id()) { + case '{': + consumeCharacter('{'); + + statements.add(parseStatements(false)); + + consumeCharacter('}'); + + break; + + case '}': + break loop; + + case 'k': + final String keyword = ((KeywordToken) current).value; + switch (keyword.charAt(0)) { + case 'i': { // if + ++position; + final RValue condition = parseBracket(); + final RValue truePart = parseStatements(true); + final RValue falsePart; + + if (hasKeyword("else")) { + ++position; + falsePart = parseStatements(true); + } else { + falsePart = null; + } + + statements.add(new Conditional(current.getPosition(), condition, truePart, falsePart)); + break; + } + + case 'w': { // while + ++position; + final RValue condition = parseBracket(); + final RValue body = parseStatements(true); + + statements.add(new While(current.getPosition(), condition, body, false)); + break; + } + + case 'd': { // do/default + if (hasKeyword("default")) { + break loop; + } + + ++position; + final RValue body = parseStatements(true); + + consumeKeyword("while"); + + final RValue condition = parseBracket(); + + statements.add(new While(current.getPosition(), condition, body, true)); + + expectSemicolon = true; + break; + } + + case 'f': { // for + ++position; + consumeCharacter('('); + int oldPosition = position; + final RValue init = parseExpression(true); + //if ((init instanceof LValue) && ) + if (peek().id() == ';') { + ++position; + final RValue condition = parseExpression(true); + consumeCharacter(';'); + final RValue increment = parseExpression(true); + consumeCharacter(')'); + final RValue body = parseStatements(true); + + statements.add(new For(current.getPosition(), init, condition, increment, body)); + } else { + position = oldPosition; + + final Token variableToken = peek(); + if (!(variableToken instanceof IdentifierToken)) { + throw new ParserException(variableToken.getPosition(), "Expected identifier"); + } + + RValue variable = expression.getVariable(((IdentifierToken) variableToken).value, true); + if (!(variable instanceof LValue)) { + throw new ParserException(variableToken.getPosition(), "Expected variable"); + } + ++position; + + final Token equalsToken = peek(); + if (!(equalsToken instanceof OperatorToken) || !((OperatorToken) equalsToken).operator.equals("=")) { + throw new ParserException(variableToken.getPosition(), "Expected '=' or a term and ';'"); + } + ++position; + + final RValue first = parseExpression(true); + consumeCharacter(','); + final RValue last = parseExpression(true); + consumeCharacter(')'); + final RValue body = parseStatements(true); + + statements.add(new SimpleFor(current.getPosition(), (LValue) variable, first, last, body)); + } // switch (keyword.charAt(0)) + break; + } + + case 'b': // break + ++position; + statements.add(new Break(current.getPosition(), false)); + break; + + case 'c': // continue/case + if (hasKeyword("case")) { + break loop; + } + + ++position; + statements.add(new Break(current.getPosition(), true)); + break; + + case 'r': // return + ++position; + statements.add(new Return(current.getPosition(), parseExpression(true))); + + expectSemicolon = true; + break; + + case 's': // switch + ++position; + final RValue parameter = parseBracket(); + final List values = new ArrayList(); + final List caseStatements = new ArrayList(); + RValue defaultCase = null; + + consumeCharacter('{'); + while (peek().id() != '}') { + if (position >= tokens.size()) { + throw new ParserException(current.getPosition(), "Expected '}' instead of EOF"); + } + if (defaultCase != null) { + throw new ParserException(current.getPosition(), "Expected '}' instead of " + peek()); + } + + if (hasKeyword("case")) { + ++position; + + final Token valueToken = peek(); + if (!(valueToken instanceof NumberToken)) { + throw new ParserException(current.getPosition(), "Expected number instead of " + peek()); + } + + ++position; + + values.add(((NumberToken) valueToken).value); + + consumeCharacter(':'); + caseStatements.add(parseStatements(false)); + } else if (hasKeyword("default")) { + ++position; + + consumeCharacter(':'); + defaultCase = parseStatements(false); + } else { + throw new ParserException(current.getPosition(), "Expected 'case' or 'default' instead of " + peek()); + } + } + consumeCharacter('}'); + + statements.add(new Switch(current.getPosition(), parameter, values, caseStatements, defaultCase)); + break; + + default: + throw new ParserException(current.getPosition(), "Unexpected keyword '" + keyword + "'"); + } + + break; + + default: + statements.add(parseExpression(true)); + + expectSemicolon = true; + } // switch (current.id()) + + if (expectSemicolon) { + if (peek().id() == ';') { + ++position; + } else { + break; + } + } + + if (singleStatement) { + break; + } + } // while (position < tokens.size()) + + switch (statements.size()) { + case 0: + if (singleStatement) { + throw new ParserException(peek().getPosition(), "Statement expected."); + } + + return new Sequence(peek().getPosition()); + + case 1: + return statements.get(0); + + default: + return new Sequence(peek().getPosition(), statements.toArray(new RValue[statements.size()])); + } + } + + private final RValue parseExpression(boolean canBeEmpty) throws ParserException { + LinkedList halfProcessed = new LinkedList(); + + // process brackets, numbers, functions, variables and detect prefix operators + boolean expressionStart = true; + loop: while (position < tokens.size()) { + final Token current = peek(); + + switch (current.id()) { + case '0': + halfProcessed.add(new Constant(current.getPosition(), ((NumberToken) current).value)); + ++position; + expressionStart = false; + break; + + case 'i': + final IdentifierToken identifierToken = (IdentifierToken) current; + ++position; + + final Token next = peek(); + if (next.id() == '(') { + halfProcessed.add(parseFunctionCall(identifierToken)); + } else { + final RValue variable = expression.getVariable(identifierToken.value, false); + if (variable == null) { + halfProcessed.add(new UnboundVariable(identifierToken.getPosition(), identifierToken.value)); + } else { + halfProcessed.add(variable); + } + } + expressionStart = false; + break; + + case '(': + halfProcessed.add(parseBracket()); + expressionStart = false; + break; + + case ',': + case ')': + case '}': + case ';': + break loop; + + case 'o': + if (expressionStart) { + // Preprocess prefix operators into unary operators + halfProcessed.add(new UnaryOperator((OperatorToken) current)); + } else { + halfProcessed.add(current); + } + ++position; + expressionStart = true; + break; + + default: + halfProcessed.add(current); + ++position; + expressionStart = false; + break; + } + } + + if (halfProcessed.isEmpty() && canBeEmpty) { + return new Sequence(peek().getPosition()); + } + + return ParserProcessors.processExpression(halfProcessed); + } + + + private Token peek() { + if (position >= tokens.size()) { + return new NullToken(tokens.get(tokens.size() - 1).getPosition() + 1); + } + + return tokens.get(position); + } + + private Function parseFunctionCall(IdentifierToken identifierToken) throws ParserException { + consumeCharacter('('); + + try { + if (peek().id() == ')') { + ++position; + return Functions.getFunction(identifierToken.getPosition(), identifierToken.value); + } + + List args = new ArrayList(); + + loop: while (true) { + args.add(parseExpression(false)); + + final Token current = peek(); + ++position; + + switch (current.id()) { + case ',': + continue; + + case ')': + break loop; + + default: + throw new ParserException(current.getPosition(), "Unmatched opening bracket"); + } + } + + return Functions.getFunction(identifierToken.getPosition(), identifierToken.value, args.toArray(new RValue[args.size()])); + } catch (NoSuchMethodException e) { + throw new ParserException(identifierToken.getPosition(), "Function '" + identifierToken.value + "' not found", e); + } + } + + private final RValue parseBracket() throws ParserException { + consumeCharacter('('); + + final RValue ret = parseExpression(false); + + consumeCharacter(')'); + + return ret; + } + + private boolean hasKeyword(String keyword) { + final Token next = peek(); + if (!(next instanceof KeywordToken)) { + return false; + } + return ((KeywordToken) next).value.equals(keyword); + } + + private void assertCharacter(char character) throws ParserException { + final Token next = peek(); + if (next.id() != character) { + throw new ParserException(next.getPosition(), "Expected '" + character + "'"); + } + } + + private void assertKeyword(String keyword) throws ParserException { + if (!hasKeyword(keyword)) { + throw new ParserException(peek().getPosition(), "Expected '" + keyword + "'"); + } + } + + private void consumeCharacter(char character) throws ParserException { + assertCharacter(character); + ++position; + } + + private void consumeKeyword(String keyword) throws ParserException { + assertKeyword(keyword); + ++position; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/parser/ParserException.java b/src/main/java/com/sk89q/worldedit/internal/expression/parser/ParserException.java similarity index 90% rename from src/main/java/com/sk89q/worldedit/expression/parser/ParserException.java rename to src/main/java/com/sk89q/worldedit/internal/expression/parser/ParserException.java index 6a97b6f8d..46af70bc5 100644 --- a/src/main/java/com/sk89q/worldedit/expression/parser/ParserException.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/parser/ParserException.java @@ -1,51 +1,51 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.parser; - -import com.sk89q.worldedit.expression.ExpressionException; - -/** - * Thrown when the parser encounters a problem. - * - * @author TomyLobo - */ -public class ParserException extends ExpressionException { - private static final long serialVersionUID = 1L; - - public ParserException(int position) { - super(position, getPrefix(position)); - } - - public ParserException(int position, String message, Throwable cause) { - super(position, getPrefix(position) + ": " + message, cause); - } - - public ParserException(int position, String message) { - super(position, getPrefix(position) + ": " + message); - } - - public ParserException(int position, Throwable cause) { - super(position, getPrefix(position), cause); - } - - private static String getPrefix(int position) { - return position < 0 ? "Parser error" : ("Parser error at " + (position + 1)); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.parser; + +import com.sk89q.worldedit.internal.expression.ExpressionException; + +/** + * Thrown when the parser encounters a problem. + * + * @author TomyLobo + */ +public class ParserException extends ExpressionException { + private static final long serialVersionUID = 1L; + + public ParserException(int position) { + super(position, getPrefix(position)); + } + + public ParserException(int position, String message, Throwable cause) { + super(position, getPrefix(position) + ": " + message, cause); + } + + public ParserException(int position, String message) { + super(position, getPrefix(position) + ": " + message); + } + + public ParserException(int position, Throwable cause) { + super(position, getPrefix(position), cause); + } + + private static String getPrefix(int position) { + return position < 0 ? "Parser error" : ("Parser error at " + (position + 1)); + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/parser/ParserProcessors.java b/src/main/java/com/sk89q/worldedit/internal/expression/parser/ParserProcessors.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/expression/parser/ParserProcessors.java rename to src/main/java/com/sk89q/worldedit/internal/expression/parser/ParserProcessors.java index 63b1a059e..7dfee6a38 100644 --- a/src/main/java/com/sk89q/worldedit/expression/parser/ParserProcessors.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/parser/ParserProcessors.java @@ -1,351 +1,351 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.parser; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.Map; - -import com.sk89q.worldedit.expression.Identifiable; -import com.sk89q.worldedit.expression.lexer.tokens.OperatorToken; -import com.sk89q.worldedit.expression.lexer.tokens.Token; -import com.sk89q.worldedit.expression.runtime.Conditional; -import com.sk89q.worldedit.expression.runtime.RValue; -import com.sk89q.worldedit.expression.runtime.Operators; - -/** - * Helper classfor Parser. Contains processors for statements and operators. - * - * @author TomyLobo - */ -public final class ParserProcessors { - private static final Map unaryOpMap = new HashMap(); - - private static final Map[] binaryOpMapsLA; - private static final Map[] binaryOpMapsRA; - - static { - unaryOpMap.put("-", "neg"); - unaryOpMap.put("!", "not"); - unaryOpMap.put("~", "inv"); - unaryOpMap.put("++", "inc"); - unaryOpMap.put("--", "dec"); - unaryOpMap.put("x++", "postinc"); - unaryOpMap.put("x--", "postdec"); - unaryOpMap.put("x!", "fac"); - - final Object[][][] binaryOpsLA = { - { - { "^", "pow" }, - { "**", "pow" }, - }, - { - { "*", "mul" }, - { "/", "div" }, - { "%", "mod" }, - }, - { - { "+", "add" }, - { "-", "sub" }, - }, - { - { "<<", "shl" }, - { ">>", "shr" }, - }, - { - { "<", "lth" }, - { ">", "gth" }, - { "<=", "leq" }, - { ">=", "geq" }, - }, - { - { "==", "equ" }, - { "!=", "neq" }, - { "~=", "near" }, - }, - { - { "&&", "and" }, - }, - { - { "||", "or" }, - }, - }; - final Object[][][] binaryOpsRA = { - { - { "=", "ass" }, - { "+=", "aadd" }, - { "-=", "asub" }, - { "*=", "amul" }, - { "/=", "adiv" }, - { "%=", "amod" }, - { "^=", "aexp" }, - }, - }; - - @SuppressWarnings("unchecked") - final Map[] lBinaryOpMapsLA = binaryOpMapsLA = new Map[binaryOpsLA.length]; - for (int i = 0; i < binaryOpsLA.length; ++i) { - final Object[][] a = binaryOpsLA[i]; - switch (a.length) { - case 0: - lBinaryOpMapsLA[i] = Collections.emptyMap(); - break; - - case 1: - final Object[] first = a[0]; - lBinaryOpMapsLA[i] = Collections.singletonMap((String) first[0], (String) first[1]); - break; - - default: - Map m = lBinaryOpMapsLA[i] = new HashMap(); - for (int j = 0; j < a.length; ++j) { - final Object[] element = a[j]; - m.put((String) element[0], (String) element[1]); - } - } - } - - @SuppressWarnings("unchecked") - final Map[] lBinaryOpMapsRA = binaryOpMapsRA = new Map[binaryOpsRA.length]; - for (int i = 0; i < binaryOpsRA.length; ++i) { - final Object[][] a = binaryOpsRA[i]; - switch (a.length) { - case 0: - lBinaryOpMapsRA[i] = Collections.emptyMap(); - break; - - case 1: - final Object[] first = a[0]; - lBinaryOpMapsRA[i] = Collections.singletonMap((String) first[0], (String) first[1]); - break; - - default: - Map m = lBinaryOpMapsRA[i] = new HashMap(); - for (int j = 0; j < a.length; ++j) { - final Object[] element = a[j]; - m.put((String) element[0], (String) element[1]); - } - } - } - } - - static RValue processExpression(LinkedList input) throws ParserException { - return processBinaryOpsRA(input, binaryOpMapsRA.length - 1); - } - - private static RValue processBinaryOpsLA(LinkedList input, int level) throws ParserException { - if (level < 0) { - return processUnaryOps(input); - } - - LinkedList lhs = new LinkedList(); - LinkedList rhs = new LinkedList(); - String operator = null; - - for (Iterator it = input.descendingIterator(); it.hasNext();) { - Identifiable identifiable = it.next(); - if (operator == null) { - rhs.addFirst(identifiable); - - if (!(identifiable instanceof OperatorToken)) { - continue; - } - - operator = binaryOpMapsLA[level].get(((OperatorToken) identifiable).operator); - if (operator == null) { - continue; - } - - rhs.removeFirst(); - } else { - lhs.addFirst(identifiable); - } - } - - RValue rhsInvokable = processBinaryOpsLA(rhs, level - 1); - if (operator == null) return rhsInvokable; - - RValue lhsInvokable = processBinaryOpsLA(lhs, level); - - try { - return Operators.getOperator(input.get(0).getPosition(), operator, lhsInvokable, rhsInvokable); - } catch (NoSuchMethodException e) { - final Token operatorToken = (Token) input.get(lhs.size()); - throw new ParserException(operatorToken.getPosition(), "Couldn't find operator '" + operator + "'"); - } - } - - private static RValue processBinaryOpsRA(LinkedList input, int level) throws ParserException { - if (level < 0) { - return processTernaryOps(input); - } - - LinkedList lhs = new LinkedList(); - LinkedList rhs = new LinkedList(); - String operator = null; - - for (Identifiable identifiable : input) { - if (operator == null) { - lhs.addLast(identifiable); - - if (!(identifiable instanceof OperatorToken)) { - continue; - } - - operator = binaryOpMapsRA[level].get(((OperatorToken) identifiable).operator); - if (operator == null) { - continue; - } - - lhs.removeLast(); - } else { - rhs.addLast(identifiable); - } - } - - RValue lhsInvokable = processBinaryOpsRA(lhs, level - 1); - if (operator == null) return lhsInvokable; - - RValue rhsInvokable = processBinaryOpsRA(rhs, level); - - try { - return Operators.getOperator(input.get(0).getPosition(), operator, lhsInvokable, rhsInvokable); - } catch (NoSuchMethodException e) { - final Token operatorToken = (Token) input.get(lhs.size()); - throw new ParserException(operatorToken.getPosition(), "Couldn't find operator '" + operator + "'"); - } - } - - private static RValue processTernaryOps(LinkedList input) throws ParserException { - LinkedList lhs = new LinkedList(); - LinkedList mhs = new LinkedList(); - LinkedList rhs = new LinkedList(); - - int partsFound = 0; - int conditionalsFound = 0; - - for (Identifiable identifiable : input) { - final char character = identifiable.id(); - switch (character) { - case '?': - ++conditionalsFound; - break; - case ':': - --conditionalsFound; - break; - } - - if (conditionalsFound < 0) { - throw new ParserException(identifiable.getPosition(), "Unexpected ':'"); - } - - switch (partsFound) { - case 0: - if (character == '?') { - partsFound = 1; - } else { - lhs.addLast(identifiable); - } - break; - - case 1: - if (conditionalsFound == 0 && character == ':') { - partsFound = 2; - } else { - mhs.addLast(identifiable); - } - break; - - case 2: - rhs.addLast(identifiable); - } - } - - if (partsFound < 2) { - return processBinaryOpsLA(input, binaryOpMapsLA.length - 1); - } - - RValue lhsInvokable = processBinaryOpsLA(lhs, binaryOpMapsLA.length - 1); - RValue mhsInvokable = processTernaryOps(mhs); - RValue rhsInvokable = processTernaryOps(rhs); - - return new Conditional(input.get(lhs.size()).getPosition(), lhsInvokable, mhsInvokable, rhsInvokable); - } - - private static RValue processUnaryOps(LinkedList input) throws ParserException { - // Preprocess postfix operators into unary operators - final Identifiable center; - LinkedList postfixes = new LinkedList(); - do { - if (input.isEmpty()) { - throw new ParserException(-1, "Expression missing."); - } - - final Identifiable last = input.removeLast(); - if (last instanceof OperatorToken) { - postfixes.addLast(new UnaryOperator(last.getPosition(), "x" + ((OperatorToken) last).operator)); - } else if (last instanceof UnaryOperator) { - postfixes.addLast(new UnaryOperator(last.getPosition(), "x" + ((UnaryOperator) last).operator)); - } else { - center = last; - break; - } - } while (true); - - if (!(center instanceof RValue)) { - throw new ParserException(center.getPosition(), "Expected expression, found " + center); - } - - input.addAll(postfixes); - - RValue ret = (RValue) center; - while (!input.isEmpty()) { - final Identifiable last = input.removeLast(); - final int lastPosition = last.getPosition(); - if (last instanceof UnaryOperator) { - final String operator = ((UnaryOperator) last).operator; - if (operator.equals("+")) { - continue; - } - - String opName = unaryOpMap.get(operator); - if (opName != null) { - try { - ret = Operators.getOperator(lastPosition, opName, ret); - continue; - } catch (NoSuchMethodException e) { - throw new ParserException(lastPosition, "No such prefix operator: " + operator); - } - } - } - - if (last instanceof Token) { - throw new ParserException(lastPosition, "Extra token found in expression: " + last); - } else if (last instanceof RValue) { - throw new ParserException(lastPosition, "Extra expression found: " + last); - } else { - throw new ParserException(lastPosition, "Extra element found: " + last); - } - } - return ret; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.parser; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map; + +import com.sk89q.worldedit.internal.expression.Identifiable; +import com.sk89q.worldedit.internal.expression.lexer.tokens.OperatorToken; +import com.sk89q.worldedit.internal.expression.lexer.tokens.Token; +import com.sk89q.worldedit.internal.expression.runtime.Conditional; +import com.sk89q.worldedit.internal.expression.runtime.RValue; +import com.sk89q.worldedit.internal.expression.runtime.Operators; + +/** + * Helper classfor Parser. Contains processors for statements and operators. + * + * @author TomyLobo + */ +public final class ParserProcessors { + private static final Map unaryOpMap = new HashMap(); + + private static final Map[] binaryOpMapsLA; + private static final Map[] binaryOpMapsRA; + + static { + unaryOpMap.put("-", "neg"); + unaryOpMap.put("!", "not"); + unaryOpMap.put("~", "inv"); + unaryOpMap.put("++", "inc"); + unaryOpMap.put("--", "dec"); + unaryOpMap.put("x++", "postinc"); + unaryOpMap.put("x--", "postdec"); + unaryOpMap.put("x!", "fac"); + + final Object[][][] binaryOpsLA = { + { + { "^", "pow" }, + { "**", "pow" }, + }, + { + { "*", "mul" }, + { "/", "div" }, + { "%", "mod" }, + }, + { + { "+", "add" }, + { "-", "sub" }, + }, + { + { "<<", "shl" }, + { ">>", "shr" }, + }, + { + { "<", "lth" }, + { ">", "gth" }, + { "<=", "leq" }, + { ">=", "geq" }, + }, + { + { "==", "equ" }, + { "!=", "neq" }, + { "~=", "near" }, + }, + { + { "&&", "and" }, + }, + { + { "||", "or" }, + }, + }; + final Object[][][] binaryOpsRA = { + { + { "=", "ass" }, + { "+=", "aadd" }, + { "-=", "asub" }, + { "*=", "amul" }, + { "/=", "adiv" }, + { "%=", "amod" }, + { "^=", "aexp" }, + }, + }; + + @SuppressWarnings("unchecked") + final Map[] lBinaryOpMapsLA = binaryOpMapsLA = new Map[binaryOpsLA.length]; + for (int i = 0; i < binaryOpsLA.length; ++i) { + final Object[][] a = binaryOpsLA[i]; + switch (a.length) { + case 0: + lBinaryOpMapsLA[i] = Collections.emptyMap(); + break; + + case 1: + final Object[] first = a[0]; + lBinaryOpMapsLA[i] = Collections.singletonMap((String) first[0], (String) first[1]); + break; + + default: + Map m = lBinaryOpMapsLA[i] = new HashMap(); + for (int j = 0; j < a.length; ++j) { + final Object[] element = a[j]; + m.put((String) element[0], (String) element[1]); + } + } + } + + @SuppressWarnings("unchecked") + final Map[] lBinaryOpMapsRA = binaryOpMapsRA = new Map[binaryOpsRA.length]; + for (int i = 0; i < binaryOpsRA.length; ++i) { + final Object[][] a = binaryOpsRA[i]; + switch (a.length) { + case 0: + lBinaryOpMapsRA[i] = Collections.emptyMap(); + break; + + case 1: + final Object[] first = a[0]; + lBinaryOpMapsRA[i] = Collections.singletonMap((String) first[0], (String) first[1]); + break; + + default: + Map m = lBinaryOpMapsRA[i] = new HashMap(); + for (int j = 0; j < a.length; ++j) { + final Object[] element = a[j]; + m.put((String) element[0], (String) element[1]); + } + } + } + } + + static RValue processExpression(LinkedList input) throws ParserException { + return processBinaryOpsRA(input, binaryOpMapsRA.length - 1); + } + + private static RValue processBinaryOpsLA(LinkedList input, int level) throws ParserException { + if (level < 0) { + return processUnaryOps(input); + } + + LinkedList lhs = new LinkedList(); + LinkedList rhs = new LinkedList(); + String operator = null; + + for (Iterator it = input.descendingIterator(); it.hasNext();) { + Identifiable identifiable = it.next(); + if (operator == null) { + rhs.addFirst(identifiable); + + if (!(identifiable instanceof OperatorToken)) { + continue; + } + + operator = binaryOpMapsLA[level].get(((OperatorToken) identifiable).operator); + if (operator == null) { + continue; + } + + rhs.removeFirst(); + } else { + lhs.addFirst(identifiable); + } + } + + RValue rhsInvokable = processBinaryOpsLA(rhs, level - 1); + if (operator == null) return rhsInvokable; + + RValue lhsInvokable = processBinaryOpsLA(lhs, level); + + try { + return Operators.getOperator(input.get(0).getPosition(), operator, lhsInvokable, rhsInvokable); + } catch (NoSuchMethodException e) { + final Token operatorToken = (Token) input.get(lhs.size()); + throw new ParserException(operatorToken.getPosition(), "Couldn't find operator '" + operator + "'"); + } + } + + private static RValue processBinaryOpsRA(LinkedList input, int level) throws ParserException { + if (level < 0) { + return processTernaryOps(input); + } + + LinkedList lhs = new LinkedList(); + LinkedList rhs = new LinkedList(); + String operator = null; + + for (Identifiable identifiable : input) { + if (operator == null) { + lhs.addLast(identifiable); + + if (!(identifiable instanceof OperatorToken)) { + continue; + } + + operator = binaryOpMapsRA[level].get(((OperatorToken) identifiable).operator); + if (operator == null) { + continue; + } + + lhs.removeLast(); + } else { + rhs.addLast(identifiable); + } + } + + RValue lhsInvokable = processBinaryOpsRA(lhs, level - 1); + if (operator == null) return lhsInvokable; + + RValue rhsInvokable = processBinaryOpsRA(rhs, level); + + try { + return Operators.getOperator(input.get(0).getPosition(), operator, lhsInvokable, rhsInvokable); + } catch (NoSuchMethodException e) { + final Token operatorToken = (Token) input.get(lhs.size()); + throw new ParserException(operatorToken.getPosition(), "Couldn't find operator '" + operator + "'"); + } + } + + private static RValue processTernaryOps(LinkedList input) throws ParserException { + LinkedList lhs = new LinkedList(); + LinkedList mhs = new LinkedList(); + LinkedList rhs = new LinkedList(); + + int partsFound = 0; + int conditionalsFound = 0; + + for (Identifiable identifiable : input) { + final char character = identifiable.id(); + switch (character) { + case '?': + ++conditionalsFound; + break; + case ':': + --conditionalsFound; + break; + } + + if (conditionalsFound < 0) { + throw new ParserException(identifiable.getPosition(), "Unexpected ':'"); + } + + switch (partsFound) { + case 0: + if (character == '?') { + partsFound = 1; + } else { + lhs.addLast(identifiable); + } + break; + + case 1: + if (conditionalsFound == 0 && character == ':') { + partsFound = 2; + } else { + mhs.addLast(identifiable); + } + break; + + case 2: + rhs.addLast(identifiable); + } + } + + if (partsFound < 2) { + return processBinaryOpsLA(input, binaryOpMapsLA.length - 1); + } + + RValue lhsInvokable = processBinaryOpsLA(lhs, binaryOpMapsLA.length - 1); + RValue mhsInvokable = processTernaryOps(mhs); + RValue rhsInvokable = processTernaryOps(rhs); + + return new Conditional(input.get(lhs.size()).getPosition(), lhsInvokable, mhsInvokable, rhsInvokable); + } + + private static RValue processUnaryOps(LinkedList input) throws ParserException { + // Preprocess postfix operators into unary operators + final Identifiable center; + LinkedList postfixes = new LinkedList(); + do { + if (input.isEmpty()) { + throw new ParserException(-1, "Expression missing."); + } + + final Identifiable last = input.removeLast(); + if (last instanceof OperatorToken) { + postfixes.addLast(new UnaryOperator(last.getPosition(), "x" + ((OperatorToken) last).operator)); + } else if (last instanceof UnaryOperator) { + postfixes.addLast(new UnaryOperator(last.getPosition(), "x" + ((UnaryOperator) last).operator)); + } else { + center = last; + break; + } + } while (true); + + if (!(center instanceof RValue)) { + throw new ParserException(center.getPosition(), "Expected expression, found " + center); + } + + input.addAll(postfixes); + + RValue ret = (RValue) center; + while (!input.isEmpty()) { + final Identifiable last = input.removeLast(); + final int lastPosition = last.getPosition(); + if (last instanceof UnaryOperator) { + final String operator = ((UnaryOperator) last).operator; + if (operator.equals("+")) { + continue; + } + + String opName = unaryOpMap.get(operator); + if (opName != null) { + try { + ret = Operators.getOperator(lastPosition, opName, ret); + continue; + } catch (NoSuchMethodException e) { + throw new ParserException(lastPosition, "No such prefix operator: " + operator); + } + } + } + + if (last instanceof Token) { + throw new ParserException(lastPosition, "Extra token found in expression: " + last); + } else if (last instanceof RValue) { + throw new ParserException(lastPosition, "Extra expression found: " + last); + } else { + throw new ParserException(lastPosition, "Extra element found: " + last); + } + } + return ret; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/parser/PseudoToken.java b/src/main/java/com/sk89q/worldedit/internal/expression/parser/PseudoToken.java similarity index 88% rename from src/main/java/com/sk89q/worldedit/expression/parser/PseudoToken.java rename to src/main/java/com/sk89q/worldedit/internal/expression/parser/PseudoToken.java index 69a176fab..b1de364a3 100644 --- a/src/main/java/com/sk89q/worldedit/expression/parser/PseudoToken.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/parser/PseudoToken.java @@ -1,43 +1,43 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.parser; - -import com.sk89q.worldedit.expression.Identifiable; - -/** - * A pseudo-token, inserted by the parser instead of the lexer. - * - * @author TomyLobo - */ -public abstract class PseudoToken implements Identifiable { - private final int position; - - public PseudoToken(int position) { - this.position = position; - } - - @Override - public abstract char id(); - - @Override - public int getPosition() { - return position; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.parser; + +import com.sk89q.worldedit.internal.expression.Identifiable; + +/** + * A pseudo-token, inserted by the parser instead of the lexer. + * + * @author TomyLobo + */ +public abstract class PseudoToken implements Identifiable { + private final int position; + + public PseudoToken(int position) { + this.position = position; + } + + @Override + public abstract char id(); + + @Override + public int getPosition() { + return position; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/parser/UnaryOperator.java b/src/main/java/com/sk89q/worldedit/internal/expression/parser/UnaryOperator.java similarity index 89% rename from src/main/java/com/sk89q/worldedit/expression/parser/UnaryOperator.java rename to src/main/java/com/sk89q/worldedit/internal/expression/parser/UnaryOperator.java index 8ab81853b..8c2c8ed0a 100644 --- a/src/main/java/com/sk89q/worldedit/expression/parser/UnaryOperator.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/parser/UnaryOperator.java @@ -1,50 +1,50 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.parser; - -import com.sk89q.worldedit.expression.lexer.tokens.OperatorToken; - -/** - * The parser uses this pseudo-token to mark operators as unary operators. - * - * @author TomyLobo - */ -public class UnaryOperator extends PseudoToken { - final String operator; - - public UnaryOperator(OperatorToken operatorToken) { - this(operatorToken.getPosition(), operatorToken.operator); - } - - public UnaryOperator(int position, String operator) { - super(position); - this.operator = operator; - } - - @Override - public char id() { - return 'p'; - } - - @Override - public String toString() { - return "UnaryOperator(" + operator + ")"; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.parser; + +import com.sk89q.worldedit.internal.expression.lexer.tokens.OperatorToken; + +/** + * The parser uses this pseudo-token to mark operators as unary operators. + * + * @author TomyLobo + */ +public class UnaryOperator extends PseudoToken { + final String operator; + + public UnaryOperator(OperatorToken operatorToken) { + this(operatorToken.getPosition(), operatorToken.operator); + } + + public UnaryOperator(int position, String operator) { + super(position); + this.operator = operator; + } + + @Override + public char id() { + return 'p'; + } + + @Override + public String toString() { + return "UnaryOperator(" + operator + ")"; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/parser/UnboundVariable.java b/src/main/java/com/sk89q/worldedit/internal/expression/parser/UnboundVariable.java similarity index 83% rename from src/main/java/com/sk89q/worldedit/expression/parser/UnboundVariable.java rename to src/main/java/com/sk89q/worldedit/internal/expression/parser/UnboundVariable.java index 13495c3f5..5a096dd23 100644 --- a/src/main/java/com/sk89q/worldedit/expression/parser/UnboundVariable.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/parser/UnboundVariable.java @@ -1,61 +1,61 @@ -package com.sk89q.worldedit.expression.parser; - -import com.sk89q.worldedit.expression.Expression; -import com.sk89q.worldedit.expression.runtime.EvaluationException; -import com.sk89q.worldedit.expression.runtime.LValue; -import com.sk89q.worldedit.expression.runtime.RValue; - -public class UnboundVariable extends PseudoToken implements LValue { - public final String name; - - public UnboundVariable(int position, String name) { - super(position); - this.name = name; - // TODO Auto-generated constructor stub - } - - @Override - public char id() { - // TODO Auto-generated method stub - return 'V'; - } - - @Override - public String toString() { - return "UnboundVariable(" + name + ")"; - } - - @Override - public double getValue() throws EvaluationException { - throw new EvaluationException(getPosition(), "Tried to evaluate unbound variable!"); - } - - @Override - public LValue optimize() throws EvaluationException { - throw new EvaluationException(getPosition(), "Tried to optimize unbound variable!"); - } - - @Override - public double assign(double value) throws EvaluationException { - throw new EvaluationException(getPosition(), "Tried to assign unbound variable!"); - } - - public RValue bind(Expression expression, boolean isLValue) throws ParserException { - final RValue variable = expression.getVariable(name, isLValue); - if (variable == null) { - throw new ParserException(getPosition(), "Variable '" + name + "' not found"); - } - - return variable; - } - - @Override - public LValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { - final RValue variable = expression.getVariable(name, preferLValue); - if (variable == null) { - throw new ParserException(getPosition(), "Variable '" + name + "' not found"); - } - - return (LValue) variable; - } -} +package com.sk89q.worldedit.internal.expression.parser; + +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; +import com.sk89q.worldedit.internal.expression.runtime.LValue; +import com.sk89q.worldedit.internal.expression.runtime.RValue; + +public class UnboundVariable extends PseudoToken implements LValue { + public final String name; + + public UnboundVariable(int position, String name) { + super(position); + this.name = name; + // TODO Auto-generated constructor stub + } + + @Override + public char id() { + // TODO Auto-generated method stub + return 'V'; + } + + @Override + public String toString() { + return "UnboundVariable(" + name + ")"; + } + + @Override + public double getValue() throws EvaluationException { + throw new EvaluationException(getPosition(), "Tried to evaluate unbound variable!"); + } + + @Override + public LValue optimize() throws EvaluationException { + throw new EvaluationException(getPosition(), "Tried to optimize unbound variable!"); + } + + @Override + public double assign(double value) throws EvaluationException { + throw new EvaluationException(getPosition(), "Tried to assign unbound variable!"); + } + + public RValue bind(Expression expression, boolean isLValue) throws ParserException { + final RValue variable = expression.getVariable(name, isLValue); + if (variable == null) { + throw new ParserException(getPosition(), "Variable '" + name + "' not found"); + } + + return variable; + } + + @Override + public LValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { + final RValue variable = expression.getVariable(name, preferLValue); + if (variable == null) { + throw new ParserException(getPosition(), "Variable '" + name + "' not found"); + } + + return (LValue) variable; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/runtime/Break.java b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Break.java similarity index 92% rename from src/main/java/com/sk89q/worldedit/expression/runtime/Break.java rename to src/main/java/com/sk89q/worldedit/internal/expression/runtime/Break.java index 2bbfba89e..77c333cf5 100644 --- a/src/main/java/com/sk89q/worldedit/expression/runtime/Break.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Break.java @@ -1,50 +1,50 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.runtime; - -/** - * A break or continue statement. - * - * @author TomyLobo - */ -public class Break extends Node { - boolean doContinue; - - public Break(int position, boolean doContinue) { - super(position); - - this.doContinue = doContinue; - } - - @Override - public double getValue() throws EvaluationException { - throw new BreakException(doContinue); - } - - @Override - public char id() { - return 'b'; - } - - @Override - public String toString() { - return doContinue ? "continue" : "break"; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.runtime; + +/** + * A break or continue statement. + * + * @author TomyLobo + */ +public class Break extends Node { + boolean doContinue; + + public Break(int position, boolean doContinue) { + super(position); + + this.doContinue = doContinue; + } + + @Override + public double getValue() throws EvaluationException { + throw new BreakException(doContinue); + } + + @Override + public char id() { + return 'b'; + } + + @Override + public String toString() { + return doContinue ? "continue" : "break"; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/runtime/BreakException.java b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/BreakException.java similarity index 93% rename from src/main/java/com/sk89q/worldedit/expression/runtime/BreakException.java rename to src/main/java/com/sk89q/worldedit/internal/expression/runtime/BreakException.java index b96ec907d..cc7fe5554 100644 --- a/src/main/java/com/sk89q/worldedit/expression/runtime/BreakException.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/BreakException.java @@ -1,38 +1,38 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.runtime; - -/** - * Thrown when a break or continue is encountered. - * Loop constructs catch this exception. - * - * @author TomyLobo - */ -public class BreakException extends EvaluationException { - private static final long serialVersionUID = 1L; - - final boolean doContinue; - - public BreakException(boolean doContinue) { - super(-1, doContinue ? "'continue' encountered outside a loop" : "'break' encountered outside a loop"); - - this.doContinue = doContinue; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.runtime; + +/** + * Thrown when a break or continue is encountered. + * Loop constructs catch this exception. + * + * @author TomyLobo + */ +public class BreakException extends EvaluationException { + private static final long serialVersionUID = 1L; + + final boolean doContinue; + + public BreakException(boolean doContinue) { + super(-1, doContinue ? "'continue' encountered outside a loop" : "'break' encountered outside a loop"); + + this.doContinue = doContinue; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/runtime/Conditional.java b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Conditional.java similarity index 91% rename from src/main/java/com/sk89q/worldedit/expression/runtime/Conditional.java rename to src/main/java/com/sk89q/worldedit/internal/expression/runtime/Conditional.java index 89c13d3de..b2a723b9b 100644 --- a/src/main/java/com/sk89q/worldedit/expression/runtime/Conditional.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Conditional.java @@ -1,93 +1,93 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.runtime; - -import com.sk89q.worldedit.expression.Expression; -import com.sk89q.worldedit.expression.parser.ParserException; - -/** - * An if/else statement or a ternary operator. - * - * @author TomyLobo - */ -public class Conditional extends Node { - private RValue condition; - private RValue truePart; - private RValue falsePart; - - public Conditional(int position, RValue condition, RValue truePart, RValue falsePart) { - super(position); - - this.condition = condition; - this.truePart = truePart; - this.falsePart = falsePart; - } - - @Override - public double getValue() throws EvaluationException { - if (condition.getValue() > 0.0) { - return truePart.getValue(); - } else { - return falsePart == null ? 0.0 : falsePart.getValue(); - } - } - - @Override - public char id() { - return 'I'; - } - - @Override - public String toString() { - if (falsePart == null) { - return "if (" + condition + ") { " + truePart + " }"; - } else if (truePart instanceof Sequence || falsePart instanceof Sequence) { - return "if (" + condition + ") { " + truePart + " } else { " + falsePart + " }"; - } else { - return "(" + condition + ") ? (" + truePart + ") : (" + falsePart + ")"; - } - } - - @Override - public RValue optimize() throws EvaluationException { - final RValue newCondition = condition.optimize(); - - if (newCondition instanceof Constant) { - if (newCondition.getValue() > 0) { - return truePart.optimize(); - } else { - return falsePart == null ? new Constant(getPosition(), 0.0) : falsePart.optimize(); - } - } - - return new Conditional(getPosition(), newCondition, truePart.optimize(), falsePart == null ? null : falsePart.optimize()); - } - - @Override - public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { - condition = condition.bindVariables(expression, false); - truePart = truePart.bindVariables(expression, false); - if (falsePart != null) { - falsePart = falsePart.bindVariables(expression, false); - } - - return this; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.runtime; + +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.parser.ParserException; + +/** + * An if/else statement or a ternary operator. + * + * @author TomyLobo + */ +public class Conditional extends Node { + private RValue condition; + private RValue truePart; + private RValue falsePart; + + public Conditional(int position, RValue condition, RValue truePart, RValue falsePart) { + super(position); + + this.condition = condition; + this.truePart = truePart; + this.falsePart = falsePart; + } + + @Override + public double getValue() throws EvaluationException { + if (condition.getValue() > 0.0) { + return truePart.getValue(); + } else { + return falsePart == null ? 0.0 : falsePart.getValue(); + } + } + + @Override + public char id() { + return 'I'; + } + + @Override + public String toString() { + if (falsePart == null) { + return "if (" + condition + ") { " + truePart + " }"; + } else if (truePart instanceof Sequence || falsePart instanceof Sequence) { + return "if (" + condition + ") { " + truePart + " } else { " + falsePart + " }"; + } else { + return "(" + condition + ") ? (" + truePart + ") : (" + falsePart + ")"; + } + } + + @Override + public RValue optimize() throws EvaluationException { + final RValue newCondition = condition.optimize(); + + if (newCondition instanceof Constant) { + if (newCondition.getValue() > 0) { + return truePart.optimize(); + } else { + return falsePart == null ? new Constant(getPosition(), 0.0) : falsePart.optimize(); + } + } + + return new Conditional(getPosition(), newCondition, truePart.optimize(), falsePart == null ? null : falsePart.optimize()); + } + + @Override + public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { + condition = condition.bindVariables(expression, false); + truePart = truePart.bindVariables(expression, false); + if (falsePart != null) { + falsePart = falsePart.bindVariables(expression, false); + } + + return this; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/runtime/Constant.java b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Constant.java similarity index 92% rename from src/main/java/com/sk89q/worldedit/expression/runtime/Constant.java rename to src/main/java/com/sk89q/worldedit/internal/expression/runtime/Constant.java index c351008d3..2de11f076 100644 --- a/src/main/java/com/sk89q/worldedit/expression/runtime/Constant.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Constant.java @@ -1,49 +1,49 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.runtime; - -/** - * A constant. - * - * @author TomyLobo - */ -public final class Constant extends Node { - private final double value; - - public Constant(int position, double value) { - super(position); - this.value = value; - } - - @Override - public double getValue() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - - @Override - public char id() { - return 'c'; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.runtime; + +/** + * A constant. + * + * @author TomyLobo + */ +public final class Constant extends Node { + private final double value; + + public Constant(int position, double value) { + super(position); + this.value = value; + } + + @Override + public double getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + @Override + public char id() { + return 'c'; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/runtime/EvaluationException.java b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/EvaluationException.java similarity index 91% rename from src/main/java/com/sk89q/worldedit/expression/runtime/EvaluationException.java rename to src/main/java/com/sk89q/worldedit/internal/expression/runtime/EvaluationException.java index 22b4aab04..d5c125fb9 100644 --- a/src/main/java/com/sk89q/worldedit/expression/runtime/EvaluationException.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/EvaluationException.java @@ -1,51 +1,51 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.runtime; - -import com.sk89q.worldedit.expression.ExpressionException; - -/** - * Thrown when there's a problem during expression evaluation. - * - * @author TomyLobo - */ -public class EvaluationException extends ExpressionException { - private static final long serialVersionUID = 1L; - - public EvaluationException(int position) { - super(position, getPrefix(position)); - } - - public EvaluationException(int position, String message, Throwable cause) { - super(position, getPrefix(position) + ": " + message, cause); - } - - public EvaluationException(int position, String message) { - super(position, getPrefix(position) + ": " + message); - } - - public EvaluationException(int position, Throwable cause) { - super(position, getPrefix(position), cause); - } - - private static String getPrefix(int position) { - return position < 0 ? "Evaluation error" : ("Evaluation error at " + (position + 1)); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.runtime; + +import com.sk89q.worldedit.internal.expression.ExpressionException; + +/** + * Thrown when there's a problem during expression evaluation. + * + * @author TomyLobo + */ +public class EvaluationException extends ExpressionException { + private static final long serialVersionUID = 1L; + + public EvaluationException(int position) { + super(position, getPrefix(position)); + } + + public EvaluationException(int position, String message, Throwable cause) { + super(position, getPrefix(position) + ": " + message, cause); + } + + public EvaluationException(int position, String message) { + super(position, getPrefix(position) + ": " + message); + } + + public EvaluationException(int position, Throwable cause) { + super(position, getPrefix(position), cause); + } + + private static String getPrefix(int position) { + return position < 0 ? "Evaluation error" : ("Evaluation error at " + (position + 1)); + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/runtime/ExpressionEnvironment.java b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/ExpressionEnvironment.java similarity index 76% rename from src/main/java/com/sk89q/worldedit/expression/runtime/ExpressionEnvironment.java rename to src/main/java/com/sk89q/worldedit/internal/expression/runtime/ExpressionEnvironment.java index 5ac316834..4e7348d01 100644 --- a/src/main/java/com/sk89q/worldedit/expression/runtime/ExpressionEnvironment.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/ExpressionEnvironment.java @@ -1,16 +1,13 @@ -package com.sk89q.worldedit.expression.runtime; - -import com.sk89q.worldedit.BlockVector; -import com.sk89q.worldedit.Vector; - -/** - * Represents a way to access blocks in a world. Has to accept non-rounded coordinates. - */ -public interface ExpressionEnvironment { - int getBlockType(double x, double y, double z); - int getBlockData(double x, double y, double z); - int getBlockTypeAbs(double x, double y, double z); - int getBlockDataAbs(double x, double y, double z); - int getBlockTypeRel(double x, double y, double z); - int getBlockDataRel(double x, double y, double z); -} +package com.sk89q.worldedit.internal.expression.runtime; + +/** + * Represents a way to access blocks in a world. Has to accept non-rounded coordinates. + */ +public interface ExpressionEnvironment { + int getBlockType(double x, double y, double z); + int getBlockData(double x, double y, double z); + int getBlockTypeAbs(double x, double y, double z); + int getBlockDataAbs(double x, double y, double z); + int getBlockTypeRel(double x, double y, double z); + int getBlockDataRel(double x, double y, double z); +} diff --git a/src/main/java/com/sk89q/worldedit/expression/runtime/For.java b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/For.java similarity index 92% rename from src/main/java/com/sk89q/worldedit/expression/runtime/For.java rename to src/main/java/com/sk89q/worldedit/internal/expression/runtime/For.java index 4164fd3a3..3257bf3de 100644 --- a/src/main/java/com/sk89q/worldedit/expression/runtime/For.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/For.java @@ -1,104 +1,104 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.runtime; - -import com.sk89q.worldedit.expression.Expression; -import com.sk89q.worldedit.expression.parser.ParserException; - -/** - * A Java/C-style for loop. - * - * @author TomyLobo - */ -public class For extends Node { - RValue init; - RValue condition; - RValue increment; - RValue body; - - public For(int position, RValue init, RValue condition, RValue increment, RValue body) { - super(position); - - this.init = init; - this.condition = condition; - this.increment = increment; - this.body = body; - } - - @Override - public double getValue() throws EvaluationException { - int iterations = 0; - double ret = 0.0; - - for (init.getValue(); condition.getValue() > 0; increment.getValue()) { - if (iterations > 256) { - throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations."); - } - ++iterations; - - try { - ret = body.getValue(); - } catch (BreakException e) { - if (e.doContinue) { - //noinspection UnnecessaryContinue - continue; - } else { - break; - } - } - } - - return ret; - } - - @Override - public char id() { - return 'F'; - } - - @Override - public String toString() { - return "for (" + init + "; " + condition + "; " + increment + ") { " + body + " }"; - } - - @Override - public RValue optimize() throws EvaluationException { - final RValue newCondition = condition.optimize(); - - if (newCondition instanceof Constant && newCondition.getValue() <= 0) { - // If the condition is always false, the loop can be flattened. - // So we run the init part and then return 0.0. - return new Sequence(getPosition(), init, new Constant(getPosition(), 0.0)).optimize(); - } - - //return new Sequence(getPosition(), init.optimize(), new While(getPosition(), condition, new Sequence(getPosition(), body, increment), false)).optimize(); - return new For(getPosition(), init.optimize(), newCondition, increment.optimize(), body.optimize()); - } - - @Override - public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { - init = init.bindVariables(expression, false); - condition = condition.bindVariables(expression, false); - increment = increment.bindVariables(expression, false); - body = body.bindVariables(expression, false); - - return this; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.runtime; + +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.parser.ParserException; + +/** + * A Java/C-style for loop. + * + * @author TomyLobo + */ +public class For extends Node { + RValue init; + RValue condition; + RValue increment; + RValue body; + + public For(int position, RValue init, RValue condition, RValue increment, RValue body) { + super(position); + + this.init = init; + this.condition = condition; + this.increment = increment; + this.body = body; + } + + @Override + public double getValue() throws EvaluationException { + int iterations = 0; + double ret = 0.0; + + for (init.getValue(); condition.getValue() > 0; increment.getValue()) { + if (iterations > 256) { + throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations."); + } + ++iterations; + + try { + ret = body.getValue(); + } catch (BreakException e) { + if (e.doContinue) { + //noinspection UnnecessaryContinue + continue; + } else { + break; + } + } + } + + return ret; + } + + @Override + public char id() { + return 'F'; + } + + @Override + public String toString() { + return "for (" + init + "; " + condition + "; " + increment + ") { " + body + " }"; + } + + @Override + public RValue optimize() throws EvaluationException { + final RValue newCondition = condition.optimize(); + + if (newCondition instanceof Constant && newCondition.getValue() <= 0) { + // If the condition is always false, the loop can be flattened. + // So we run the init part and then return 0.0. + return new Sequence(getPosition(), init, new Constant(getPosition(), 0.0)).optimize(); + } + + //return new Sequence(getPosition(), init.optimize(), new While(getPosition(), condition, new Sequence(getPosition(), body, increment), false)).optimize(); + return new For(getPosition(), init.optimize(), newCondition, increment.optimize(), body.optimize()); + } + + @Override + public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { + init = init.bindVariables(expression, false); + condition = condition.bindVariables(expression, false); + increment = increment.bindVariables(expression, false); + body = body.bindVariables(expression, false); + + return this; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/runtime/Function.java b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Function.java similarity index 93% rename from src/main/java/com/sk89q/worldedit/expression/runtime/Function.java rename to src/main/java/com/sk89q/worldedit/internal/expression/runtime/Function.java index f4cb56719..ab656e5fd 100644 --- a/src/main/java/com/sk89q/worldedit/expression/runtime/Function.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Function.java @@ -1,123 +1,123 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.runtime; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -import com.sk89q.worldedit.expression.Expression; -import com.sk89q.worldedit.expression.parser.ParserException; - -/** - * Wrapper for a Java method and its arguments (other Nodes) - * - * @author TomyLobo - */ -public class Function extends Node { - /** - * Add this annotation on functions that don't always return the same value - * for the same inputs and on functions with side-effects. - */ - @Retention(RetentionPolicy.RUNTIME) - public @interface Dynamic { } - - final Method method; - final RValue[] args; - - Function(int position, Method method, RValue... args) { - super(position); - this.method = method; - this.args = args; - } - - @Override - public final double getValue() throws EvaluationException { - return invokeMethod(method, args); - } - - protected static final double invokeMethod(Method method, Object[] args) throws EvaluationException { - try { - return (Double) method.invoke(null, args); - } catch (InvocationTargetException e) { - if (e.getTargetException() instanceof EvaluationException) { - throw (EvaluationException) e.getTargetException(); - } - throw new EvaluationException(-1, "Exception caught while evaluating expression", e.getTargetException()); - } catch (IllegalAccessException e) { - throw new EvaluationException(-1, "Internal error while evaluating expression", e); - } - } - - @Override - public String toString() { - final StringBuilder ret = new StringBuilder(method.getName()).append('('); - boolean first = true; - for (Object obj : args) { - if (!first) { - ret.append(", "); - } - first = false; - ret.append(obj); - } - return ret.append(')').toString(); - } - - @Override - public char id() { - return 'f'; - } - - @Override - public RValue optimize() throws EvaluationException { - final RValue[] optimizedArgs = new RValue[args.length]; - boolean optimizable = !method.isAnnotationPresent(Dynamic.class); - int position = getPosition(); - for (int i = 0; i < args.length; ++i) { - final RValue optimized = optimizedArgs[i] = args[i].optimize(); - - if (!(optimized instanceof Constant)) { - optimizable = false; - } - - if (optimized.getPosition() < position) { - position = optimized.getPosition(); - } - } - - if (optimizable) { - return new Constant(position, invokeMethod(method, optimizedArgs)); - } else { - return new Function(position, method, optimizedArgs); - } - } - - @Override - public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { - final Class[] parameters = method.getParameterTypes(); - for (int i = 0; i < args.length; ++i) { - final boolean argumentPrefersLValue = LValue.class.isAssignableFrom(parameters[i]); - args[i] = args[i].bindVariables(expression, argumentPrefersLValue); - } - - return this; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.runtime; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.parser.ParserException; + +/** + * Wrapper for a Java method and its arguments (other Nodes) + * + * @author TomyLobo + */ +public class Function extends Node { + /** + * Add this annotation on functions that don't always return the same value + * for the same inputs and on functions with side-effects. + */ + @Retention(RetentionPolicy.RUNTIME) + public @interface Dynamic { } + + final Method method; + final RValue[] args; + + Function(int position, Method method, RValue... args) { + super(position); + this.method = method; + this.args = args; + } + + @Override + public final double getValue() throws EvaluationException { + return invokeMethod(method, args); + } + + protected static final double invokeMethod(Method method, Object[] args) throws EvaluationException { + try { + return (Double) method.invoke(null, args); + } catch (InvocationTargetException e) { + if (e.getTargetException() instanceof EvaluationException) { + throw (EvaluationException) e.getTargetException(); + } + throw new EvaluationException(-1, "Exception caught while evaluating expression", e.getTargetException()); + } catch (IllegalAccessException e) { + throw new EvaluationException(-1, "Internal error while evaluating expression", e); + } + } + + @Override + public String toString() { + final StringBuilder ret = new StringBuilder(method.getName()).append('('); + boolean first = true; + for (Object obj : args) { + if (!first) { + ret.append(", "); + } + first = false; + ret.append(obj); + } + return ret.append(')').toString(); + } + + @Override + public char id() { + return 'f'; + } + + @Override + public RValue optimize() throws EvaluationException { + final RValue[] optimizedArgs = new RValue[args.length]; + boolean optimizable = !method.isAnnotationPresent(Dynamic.class); + int position = getPosition(); + for (int i = 0; i < args.length; ++i) { + final RValue optimized = optimizedArgs[i] = args[i].optimize(); + + if (!(optimized instanceof Constant)) { + optimizable = false; + } + + if (optimized.getPosition() < position) { + position = optimized.getPosition(); + } + } + + if (optimizable) { + return new Constant(position, invokeMethod(method, optimizedArgs)); + } else { + return new Function(position, method, optimizedArgs); + } + } + + @Override + public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { + final Class[] parameters = method.getParameterTypes(); + for (int i = 0; i < args.length; ++i) { + final boolean argumentPrefersLValue = LValue.class.isAssignableFrom(parameters[i]); + args[i] = args[i].bindVariables(expression, argumentPrefersLValue); + } + + return this; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/runtime/Functions.java b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Functions.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/expression/runtime/Functions.java rename to src/main/java/com/sk89q/worldedit/internal/expression/runtime/Functions.java index 51d1a2f36..637d2a2d5 100644 --- a/src/main/java/com/sk89q/worldedit/expression/runtime/Functions.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Functions.java @@ -1,439 +1,439 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.runtime; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; - -import com.sk89q.worldedit.expression.Expression; -import com.sk89q.worldedit.expression.runtime.Function.Dynamic; - -/** - * Contains all functions that can be used in expressions. - * - * @author TomyLobo - */ -@SuppressWarnings("UnusedDeclaration") -public final class Functions { - private static class Overload { - private final Method method; - private final int mask; - private final boolean isSetter; - - public Overload(Method method) throws IllegalArgumentException { - this.method = method; - - boolean isSetter = false; - int accum = 0; - Class[] parameters = method.getParameterTypes(); - for (Class parameter : parameters) { - if (isSetter) { - throw new IllegalArgumentException("Method takes arguments that can't be cast to RValue."); - } - - if (double.class.equals(parameter)) { - isSetter = true; - continue; - } - - if (!RValue.class.isAssignableFrom(parameter)) { - throw new IllegalArgumentException("Method takes arguments that can't be cast to RValue."); - } - - accum <<= 2; - - if (LValue.class.isAssignableFrom(parameter)) { - accum |= 3; - } else { - accum |= 1; - } - } - mask = accum; - this.isSetter = isSetter; - } - - public boolean matches(boolean isSetter, RValue... args) { - if (this.isSetter != isSetter) { - return false; - } - - if (this.method.getParameterTypes().length != args.length) { // TODO: optimize - return false; - } - - int accum = 0; - for (RValue argument : args) { - accum <<= 2; - - if (argument instanceof LValue) { - accum |= 3; - } else { - accum |= 1; - } - } - - return (accum & mask) == mask; - } - } - - public static Function getFunction(int position, String name, RValue... args) throws NoSuchMethodException { - final Method getter = getMethod(name, false, args); - try { - Method setter = getMethod(name, true, args); - return new LValueFunction(position, getter, setter, args); - } catch (NoSuchMethodException e) { - return new Function(position, getter, args); - } - } - - private static Method getMethod(String name, boolean isSetter, RValue... args) throws NoSuchMethodException { - final List overloads = functions.get(name); - if (overloads != null) { - for (Overload overload : overloads) { - if (overload.matches(isSetter, args)) { - return overload.method; - } - } - } - - throw new NoSuchMethodException(); // TODO: return null (check for side-effects first) - } - - private static final Map> functions = new HashMap>(); - static { - for (Method method : Functions.class.getMethods()) { - try { - addFunction(method); - } catch (IllegalArgumentException ignored) { } - } - } - - - public static void addFunction(Method method) throws IllegalArgumentException { - final String methodName = method.getName(); - - Overload overload = new Overload(method); - - List overloads = functions.get(methodName); - if (overloads == null) { - functions.put(methodName, overloads = new ArrayList()); - } - - overloads.add(overload); - } - - - public static double sin(RValue x) throws EvaluationException { - return Math.sin(x.getValue()); - } - - public static double cos(RValue x) throws EvaluationException { - return Math.cos(x.getValue()); - } - - public static double tan(RValue x) throws EvaluationException { - return Math.tan(x.getValue()); - } - - - public static double asin(RValue x) throws EvaluationException { - return Math.asin(x.getValue()); - } - - public static double acos(RValue x) throws EvaluationException { - return Math.acos(x.getValue()); - } - - public static double atan(RValue x) throws EvaluationException { - return Math.atan(x.getValue()); - } - - public static double atan2(RValue y, RValue x) throws EvaluationException { - return Math.atan2(y.getValue(), x.getValue()); - } - - - public static double sinh(RValue x) throws EvaluationException { - return Math.sinh(x.getValue()); - } - - public static double cosh(RValue x) throws EvaluationException { - return Math.cosh(x.getValue()); - } - - public static double tanh(RValue x) throws EvaluationException { - return Math.tanh(x.getValue()); - } - - - public static double sqrt(RValue x) throws EvaluationException { - return Math.sqrt(x.getValue()); - } - - public static double cbrt(RValue x) throws EvaluationException { - return Math.cbrt(x.getValue()); - } - - - public static double abs(RValue x) throws EvaluationException { - return Math.abs(x.getValue()); - } - - public static double min(RValue a, RValue b) throws EvaluationException { - return Math.min(a.getValue(), b.getValue()); - } - - public static double min(RValue a, RValue b, RValue c) throws EvaluationException { - return Math.min(a.getValue(), Math.min(b.getValue(), c.getValue())); - } - - public static double max(RValue a, RValue b) throws EvaluationException { - return Math.max(a.getValue(), b.getValue()); - } - - public static double max(RValue a, RValue b, RValue c) throws EvaluationException { - return Math.max(a.getValue(), Math.max(b.getValue(), c.getValue())); - } - - - public static double ceil(RValue x) throws EvaluationException { - return Math.ceil(x.getValue()); - } - - public static double floor(RValue x) throws EvaluationException { - return Math.floor(x.getValue()); - } - - public static double rint(RValue x) throws EvaluationException { - return Math.rint(x.getValue()); - } - - public static double round(RValue x) throws EvaluationException { - return Math.round(x.getValue()); - } - - - public static double exp(RValue x) throws EvaluationException { - return Math.exp(x.getValue()); - } - - public static double ln(RValue x) throws EvaluationException { - return Math.log(x.getValue()); - } - - public static double log(RValue x) throws EvaluationException { - return Math.log(x.getValue()); - } - - public static double log10(RValue x) throws EvaluationException { - return Math.log10(x.getValue()); - } - - - public static double rotate(LValue x, LValue y, RValue angle) throws EvaluationException { - final double f = angle.getValue(); - - final double cosF = Math.cos(f); - final double sinF = Math.sin(f); - - final double xOld = x.getValue(); - final double yOld = y.getValue(); - - x.assign(xOld * cosF - yOld * sinF); - y.assign(xOld * sinF + yOld * cosF); - - return 0.0; - } - - public static double swap(LValue x, LValue y) throws EvaluationException { - final double tmp = x.getValue(); - - x.assign(y.getValue()); - y.assign(tmp); - - return 0.0; - } - - - private static final Map gmegabuf = new HashMap(); - private final Map megabuf = new HashMap(); - - private static double[] getSubBuffer(Map megabuf, Integer key) { - double[] ret = megabuf.get(key); - if (ret == null) { - megabuf.put(key, ret = new double[1024]); - } - return ret; - } - - private static double getBufferItem(final Map megabuf, final int index) { - return getSubBuffer(megabuf, index & ~1023)[index & 1023]; - } - - private static double setBufferItem(final Map megabuf, final int index, double value) { - return getSubBuffer(megabuf, index & ~1023)[index & 1023] = value; - } - - @Dynamic - public static double gmegabuf(RValue index) throws EvaluationException { - return getBufferItem(gmegabuf, (int) index.getValue()); - } - - @Dynamic - public static double gmegabuf(RValue index, double value) throws EvaluationException { - return setBufferItem(gmegabuf, (int) index.getValue(), value); - } - - @Dynamic - public static double megabuf(RValue index) throws EvaluationException { - return getBufferItem(Expression.getInstance().getFunctions().megabuf, (int) index.getValue()); - } - - @Dynamic - public static double megabuf(RValue index, double value) throws EvaluationException { - return setBufferItem(Expression.getInstance().getFunctions().megabuf, (int) index.getValue(), value); - } - - @Dynamic - public static double closest(RValue x, RValue y, RValue z, RValue index, RValue count, RValue stride) throws EvaluationException { - return findClosest( - Expression.getInstance().getFunctions().megabuf, - x.getValue(), - y.getValue(), - z.getValue(), - (int) index.getValue(), - (int) count.getValue(), - (int) stride.getValue() - ); - } - - @Dynamic - public static double gclosest(RValue x, RValue y, RValue z, RValue index, RValue count, RValue stride) throws EvaluationException { - return findClosest( - gmegabuf, - x.getValue(), - y.getValue(), - z.getValue(), - (int) index.getValue(), - (int) count.getValue(), - (int) stride.getValue() - ); - } - - private static double findClosest(Map megabuf, double x, double y, double z, int index, int count, int stride) { - int closestIndex = -1; - double minDistanceSquared = Double.MAX_VALUE; - - for (int i = 0; i < count; ++i) { - double currentX = getBufferItem(megabuf, index+0) - x; - double currentY = getBufferItem(megabuf, index+1) - y; - double currentZ = getBufferItem(megabuf, index+2) - z; - - double currentDistanceSquared = currentX*currentX + currentY*currentY + currentZ*currentZ; - - if (currentDistanceSquared < minDistanceSquared) { - minDistanceSquared = currentDistanceSquared; - closestIndex = index; - } - - index += stride; - } - - return closestIndex; - } - - - private static final Random random = new Random(); - - @Dynamic - public static double random() { - return random.nextDouble(); - } - - @Dynamic - public static double randint(RValue max) throws EvaluationException { - return random.nextInt((int) Math.floor(max.getValue())); - } - - - private static double queryInternal(RValue type, RValue data, double typeId, double dataValue) throws EvaluationException { - // Compare to input values and determine return value - final double ret = (typeId == type.getValue() && dataValue == data.getValue()) ? 1.0 : 0.0; - - if (type instanceof LValue) { - ((LValue) type).assign(typeId); - } - - if (data instanceof LValue) { - ((LValue) data).assign(dataValue); - } - - return ret; - } - - @Dynamic - public static double query(RValue x, RValue y, RValue z, RValue type, RValue data) throws EvaluationException { - final double xp = x.getValue(); - final double yp = y.getValue(); - final double zp = z.getValue(); - - final ExpressionEnvironment environment = Expression.getInstance().getEnvironment(); - - // Read values from world - final double typeId = environment.getBlockType(xp, yp, zp); - final double dataValue = environment.getBlockData(xp, yp, zp); - - return queryInternal(type, data, typeId, dataValue); - } - - @Dynamic - public static double queryAbs(RValue x, RValue y, RValue z, RValue type, RValue data) throws EvaluationException { - final double xp = x.getValue(); - final double yp = y.getValue(); - final double zp = z.getValue(); - - final ExpressionEnvironment environment = Expression.getInstance().getEnvironment(); - - // Read values from world - final double typeId = environment.getBlockTypeAbs(xp, yp, zp); - final double dataValue = environment.getBlockDataAbs(xp, yp, zp); - - return queryInternal(type, data, typeId, dataValue); - } - - @Dynamic - public static double queryRel(RValue x, RValue y, RValue z, RValue type, RValue data) throws EvaluationException { - final double xp = x.getValue(); - final double yp = y.getValue(); - final double zp = z.getValue(); - - final ExpressionEnvironment environment = Expression.getInstance().getEnvironment(); - - // Read values from world - final double typeId = environment.getBlockTypeRel(xp, yp, zp); - final double dataValue = environment.getBlockDataRel(xp, yp, zp); - - return queryInternal(type, data, typeId, dataValue); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.runtime; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.runtime.Function.Dynamic; + +/** + * Contains all functions that can be used in expressions. + * + * @author TomyLobo + */ +@SuppressWarnings("UnusedDeclaration") +public final class Functions { + private static class Overload { + private final Method method; + private final int mask; + private final boolean isSetter; + + public Overload(Method method) throws IllegalArgumentException { + this.method = method; + + boolean isSetter = false; + int accum = 0; + Class[] parameters = method.getParameterTypes(); + for (Class parameter : parameters) { + if (isSetter) { + throw new IllegalArgumentException("Method takes arguments that can't be cast to RValue."); + } + + if (double.class.equals(parameter)) { + isSetter = true; + continue; + } + + if (!RValue.class.isAssignableFrom(parameter)) { + throw new IllegalArgumentException("Method takes arguments that can't be cast to RValue."); + } + + accum <<= 2; + + if (LValue.class.isAssignableFrom(parameter)) { + accum |= 3; + } else { + accum |= 1; + } + } + mask = accum; + this.isSetter = isSetter; + } + + public boolean matches(boolean isSetter, RValue... args) { + if (this.isSetter != isSetter) { + return false; + } + + if (this.method.getParameterTypes().length != args.length) { // TODO: optimize + return false; + } + + int accum = 0; + for (RValue argument : args) { + accum <<= 2; + + if (argument instanceof LValue) { + accum |= 3; + } else { + accum |= 1; + } + } + + return (accum & mask) == mask; + } + } + + public static Function getFunction(int position, String name, RValue... args) throws NoSuchMethodException { + final Method getter = getMethod(name, false, args); + try { + Method setter = getMethod(name, true, args); + return new LValueFunction(position, getter, setter, args); + } catch (NoSuchMethodException e) { + return new Function(position, getter, args); + } + } + + private static Method getMethod(String name, boolean isSetter, RValue... args) throws NoSuchMethodException { + final List overloads = functions.get(name); + if (overloads != null) { + for (Overload overload : overloads) { + if (overload.matches(isSetter, args)) { + return overload.method; + } + } + } + + throw new NoSuchMethodException(); // TODO: return null (check for side-effects first) + } + + private static final Map> functions = new HashMap>(); + static { + for (Method method : Functions.class.getMethods()) { + try { + addFunction(method); + } catch (IllegalArgumentException ignored) { } + } + } + + + public static void addFunction(Method method) throws IllegalArgumentException { + final String methodName = method.getName(); + + Overload overload = new Overload(method); + + List overloads = functions.get(methodName); + if (overloads == null) { + functions.put(methodName, overloads = new ArrayList()); + } + + overloads.add(overload); + } + + + public static double sin(RValue x) throws EvaluationException { + return Math.sin(x.getValue()); + } + + public static double cos(RValue x) throws EvaluationException { + return Math.cos(x.getValue()); + } + + public static double tan(RValue x) throws EvaluationException { + return Math.tan(x.getValue()); + } + + + public static double asin(RValue x) throws EvaluationException { + return Math.asin(x.getValue()); + } + + public static double acos(RValue x) throws EvaluationException { + return Math.acos(x.getValue()); + } + + public static double atan(RValue x) throws EvaluationException { + return Math.atan(x.getValue()); + } + + public static double atan2(RValue y, RValue x) throws EvaluationException { + return Math.atan2(y.getValue(), x.getValue()); + } + + + public static double sinh(RValue x) throws EvaluationException { + return Math.sinh(x.getValue()); + } + + public static double cosh(RValue x) throws EvaluationException { + return Math.cosh(x.getValue()); + } + + public static double tanh(RValue x) throws EvaluationException { + return Math.tanh(x.getValue()); + } + + + public static double sqrt(RValue x) throws EvaluationException { + return Math.sqrt(x.getValue()); + } + + public static double cbrt(RValue x) throws EvaluationException { + return Math.cbrt(x.getValue()); + } + + + public static double abs(RValue x) throws EvaluationException { + return Math.abs(x.getValue()); + } + + public static double min(RValue a, RValue b) throws EvaluationException { + return Math.min(a.getValue(), b.getValue()); + } + + public static double min(RValue a, RValue b, RValue c) throws EvaluationException { + return Math.min(a.getValue(), Math.min(b.getValue(), c.getValue())); + } + + public static double max(RValue a, RValue b) throws EvaluationException { + return Math.max(a.getValue(), b.getValue()); + } + + public static double max(RValue a, RValue b, RValue c) throws EvaluationException { + return Math.max(a.getValue(), Math.max(b.getValue(), c.getValue())); + } + + + public static double ceil(RValue x) throws EvaluationException { + return Math.ceil(x.getValue()); + } + + public static double floor(RValue x) throws EvaluationException { + return Math.floor(x.getValue()); + } + + public static double rint(RValue x) throws EvaluationException { + return Math.rint(x.getValue()); + } + + public static double round(RValue x) throws EvaluationException { + return Math.round(x.getValue()); + } + + + public static double exp(RValue x) throws EvaluationException { + return Math.exp(x.getValue()); + } + + public static double ln(RValue x) throws EvaluationException { + return Math.log(x.getValue()); + } + + public static double log(RValue x) throws EvaluationException { + return Math.log(x.getValue()); + } + + public static double log10(RValue x) throws EvaluationException { + return Math.log10(x.getValue()); + } + + + public static double rotate(LValue x, LValue y, RValue angle) throws EvaluationException { + final double f = angle.getValue(); + + final double cosF = Math.cos(f); + final double sinF = Math.sin(f); + + final double xOld = x.getValue(); + final double yOld = y.getValue(); + + x.assign(xOld * cosF - yOld * sinF); + y.assign(xOld * sinF + yOld * cosF); + + return 0.0; + } + + public static double swap(LValue x, LValue y) throws EvaluationException { + final double tmp = x.getValue(); + + x.assign(y.getValue()); + y.assign(tmp); + + return 0.0; + } + + + private static final Map gmegabuf = new HashMap(); + private final Map megabuf = new HashMap(); + + private static double[] getSubBuffer(Map megabuf, Integer key) { + double[] ret = megabuf.get(key); + if (ret == null) { + megabuf.put(key, ret = new double[1024]); + } + return ret; + } + + private static double getBufferItem(final Map megabuf, final int index) { + return getSubBuffer(megabuf, index & ~1023)[index & 1023]; + } + + private static double setBufferItem(final Map megabuf, final int index, double value) { + return getSubBuffer(megabuf, index & ~1023)[index & 1023] = value; + } + + @Dynamic + public static double gmegabuf(RValue index) throws EvaluationException { + return getBufferItem(gmegabuf, (int) index.getValue()); + } + + @Dynamic + public static double gmegabuf(RValue index, double value) throws EvaluationException { + return setBufferItem(gmegabuf, (int) index.getValue(), value); + } + + @Dynamic + public static double megabuf(RValue index) throws EvaluationException { + return getBufferItem(Expression.getInstance().getFunctions().megabuf, (int) index.getValue()); + } + + @Dynamic + public static double megabuf(RValue index, double value) throws EvaluationException { + return setBufferItem(Expression.getInstance().getFunctions().megabuf, (int) index.getValue(), value); + } + + @Dynamic + public static double closest(RValue x, RValue y, RValue z, RValue index, RValue count, RValue stride) throws EvaluationException { + return findClosest( + Expression.getInstance().getFunctions().megabuf, + x.getValue(), + y.getValue(), + z.getValue(), + (int) index.getValue(), + (int) count.getValue(), + (int) stride.getValue() + ); + } + + @Dynamic + public static double gclosest(RValue x, RValue y, RValue z, RValue index, RValue count, RValue stride) throws EvaluationException { + return findClosest( + gmegabuf, + x.getValue(), + y.getValue(), + z.getValue(), + (int) index.getValue(), + (int) count.getValue(), + (int) stride.getValue() + ); + } + + private static double findClosest(Map megabuf, double x, double y, double z, int index, int count, int stride) { + int closestIndex = -1; + double minDistanceSquared = Double.MAX_VALUE; + + for (int i = 0; i < count; ++i) { + double currentX = getBufferItem(megabuf, index+0) - x; + double currentY = getBufferItem(megabuf, index+1) - y; + double currentZ = getBufferItem(megabuf, index+2) - z; + + double currentDistanceSquared = currentX*currentX + currentY*currentY + currentZ*currentZ; + + if (currentDistanceSquared < minDistanceSquared) { + minDistanceSquared = currentDistanceSquared; + closestIndex = index; + } + + index += stride; + } + + return closestIndex; + } + + + private static final Random random = new Random(); + + @Dynamic + public static double random() { + return random.nextDouble(); + } + + @Dynamic + public static double randint(RValue max) throws EvaluationException { + return random.nextInt((int) Math.floor(max.getValue())); + } + + + private static double queryInternal(RValue type, RValue data, double typeId, double dataValue) throws EvaluationException { + // Compare to input values and determine return value + final double ret = (typeId == type.getValue() && dataValue == data.getValue()) ? 1.0 : 0.0; + + if (type instanceof LValue) { + ((LValue) type).assign(typeId); + } + + if (data instanceof LValue) { + ((LValue) data).assign(dataValue); + } + + return ret; + } + + @Dynamic + public static double query(RValue x, RValue y, RValue z, RValue type, RValue data) throws EvaluationException { + final double xp = x.getValue(); + final double yp = y.getValue(); + final double zp = z.getValue(); + + final ExpressionEnvironment environment = Expression.getInstance().getEnvironment(); + + // Read values from world + final double typeId = environment.getBlockType(xp, yp, zp); + final double dataValue = environment.getBlockData(xp, yp, zp); + + return queryInternal(type, data, typeId, dataValue); + } + + @Dynamic + public static double queryAbs(RValue x, RValue y, RValue z, RValue type, RValue data) throws EvaluationException { + final double xp = x.getValue(); + final double yp = y.getValue(); + final double zp = z.getValue(); + + final ExpressionEnvironment environment = Expression.getInstance().getEnvironment(); + + // Read values from world + final double typeId = environment.getBlockTypeAbs(xp, yp, zp); + final double dataValue = environment.getBlockDataAbs(xp, yp, zp); + + return queryInternal(type, data, typeId, dataValue); + } + + @Dynamic + public static double queryRel(RValue x, RValue y, RValue z, RValue type, RValue data) throws EvaluationException { + final double xp = x.getValue(); + final double yp = y.getValue(); + final double zp = z.getValue(); + + final ExpressionEnvironment environment = Expression.getInstance().getEnvironment(); + + // Read values from world + final double typeId = environment.getBlockTypeRel(xp, yp, zp); + final double dataValue = environment.getBlockDataRel(xp, yp, zp); + + return queryInternal(type, data, typeId, dataValue); + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/runtime/LValue.java b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/LValue.java similarity index 85% rename from src/main/java/com/sk89q/worldedit/expression/runtime/LValue.java rename to src/main/java/com/sk89q/worldedit/internal/expression/runtime/LValue.java index d909e7fb4..53adcc9f4 100644 --- a/src/main/java/com/sk89q/worldedit/expression/runtime/LValue.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/LValue.java @@ -1,36 +1,36 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.runtime; - -import com.sk89q.worldedit.expression.Expression; -import com.sk89q.worldedit.expression.parser.ParserException; - -/** - * A value that can be used on the left side of an assignment. - * - * @author TomyLobo - */ -public interface LValue extends RValue { - public double assign(double value) throws EvaluationException; - - public LValue optimize() throws EvaluationException; - - public LValue bindVariables(Expression expression, boolean preferLValue) throws ParserException; -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.runtime; + +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.parser.ParserException; + +/** + * A value that can be used on the left side of an assignment. + * + * @author TomyLobo + */ +public interface LValue extends RValue { + public double assign(double value) throws EvaluationException; + + public LValue optimize() throws EvaluationException; + + public LValue bindVariables(Expression expression, boolean preferLValue) throws ParserException; +} diff --git a/src/main/java/com/sk89q/worldedit/expression/runtime/LValueFunction.java b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/LValueFunction.java similarity index 90% rename from src/main/java/com/sk89q/worldedit/expression/runtime/LValueFunction.java rename to src/main/java/com/sk89q/worldedit/internal/expression/runtime/LValueFunction.java index ce13fea7f..a9f678b2f 100644 --- a/src/main/java/com/sk89q/worldedit/expression/runtime/LValueFunction.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/LValueFunction.java @@ -1,76 +1,76 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.runtime; - -import java.lang.reflect.Method; - -import com.sk89q.worldedit.expression.Expression; -import com.sk89q.worldedit.expression.parser.ParserException; - -/** - * Wrapper for a pair of Java methods and their arguments (other Nodes), forming an LValue - * - * @author TomyLobo - */ -public class LValueFunction extends Function implements LValue { - private final Object[] setterArgs; - private final Method setter; - - LValueFunction(int position, Method getter, Method setter, RValue... args) { - super(position, getter, args); - assert (getter.isAnnotationPresent(Dynamic.class)); - - setterArgs = new Object[args.length + 1]; - System.arraycopy(args, 0, setterArgs, 0, args.length); - this.setter = setter; - } - - @Override - public char id() { - return 'l'; - } - - @Override - public double assign(double value) throws EvaluationException { - setterArgs[setterArgs.length - 1] = value; - return invokeMethod(setter, setterArgs); - } - - @Override - public LValue optimize() throws EvaluationException { - final RValue optimized = super.optimize(); - if (optimized == this) { - return this; - } - - if (optimized instanceof Function) { - return new LValueFunction(optimized.getPosition(), method, setter, ((Function) optimized).args); - } - - return (LValue) optimized; - } - - @Override - public LValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { - super.bindVariables(expression, preferLValue); - - return this; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.runtime; + +import java.lang.reflect.Method; + +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.parser.ParserException; + +/** + * Wrapper for a pair of Java methods and their arguments (other Nodes), forming an LValue + * + * @author TomyLobo + */ +public class LValueFunction extends Function implements LValue { + private final Object[] setterArgs; + private final Method setter; + + LValueFunction(int position, Method getter, Method setter, RValue... args) { + super(position, getter, args); + assert (getter.isAnnotationPresent(Dynamic.class)); + + setterArgs = new Object[args.length + 1]; + System.arraycopy(args, 0, setterArgs, 0, args.length); + this.setter = setter; + } + + @Override + public char id() { + return 'l'; + } + + @Override + public double assign(double value) throws EvaluationException { + setterArgs[setterArgs.length - 1] = value; + return invokeMethod(setter, setterArgs); + } + + @Override + public LValue optimize() throws EvaluationException { + final RValue optimized = super.optimize(); + if (optimized == this) { + return this; + } + + if (optimized instanceof Function) { + return new LValueFunction(optimized.getPosition(), method, setter, ((Function) optimized).args); + } + + return (LValue) optimized; + } + + @Override + public LValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { + super.bindVariables(expression, preferLValue); + + return this; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/runtime/Node.java b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Node.java similarity index 86% rename from src/main/java/com/sk89q/worldedit/expression/runtime/Node.java rename to src/main/java/com/sk89q/worldedit/internal/expression/runtime/Node.java index e0c7d184a..dd280756a 100644 --- a/src/main/java/com/sk89q/worldedit/expression/runtime/Node.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Node.java @@ -1,53 +1,53 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.runtime; - -import com.sk89q.worldedit.expression.Expression; -import com.sk89q.worldedit.expression.parser.ParserException; - -/** - * A node in the execution tree of an expression. - * - * @author TomyLobo - */ -public abstract class Node implements RValue { - private final int position; - - public Node(int position) { - this.position = position; - } - - @Override - public abstract String toString(); - - public RValue optimize() throws EvaluationException { - return this; - } - - @Override - public final int getPosition() { - return position; - } - - @Override - public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { - return this; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.runtime; + +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.parser.ParserException; + +/** + * A node in the execution tree of an expression. + * + * @author TomyLobo + */ +public abstract class Node implements RValue { + private final int position; + + public Node(int position) { + this.position = position; + } + + @Override + public abstract String toString(); + + public RValue optimize() throws EvaluationException { + return this; + } + + @Override + public final int getPosition() { + return position; + } + + @Override + public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { + return this; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/runtime/Operators.java b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Operators.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/expression/runtime/Operators.java rename to src/main/java/com/sk89q/worldedit/internal/expression/runtime/Operators.java index 3b3556d77..e8739043b 100644 --- a/src/main/java/com/sk89q/worldedit/expression/runtime/Operators.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Operators.java @@ -1,225 +1,225 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.runtime; - -/** - * Contains all unary and binary operators. - * - * @author TomyLobo - */ -@SuppressWarnings("UnusedDeclaration") -public final class Operators { - public static Function getOperator(int position, String name, RValue lhs, RValue rhs) throws NoSuchMethodException { - if (lhs instanceof LValue) { - try { - return new Function(position, Operators.class.getMethod(name, LValue.class, RValue.class), lhs, rhs); - } catch (NoSuchMethodException ignored) { } - } - return new Function(position, Operators.class.getMethod(name, RValue.class, RValue.class), lhs, rhs); - } - - public static Function getOperator(int position, String name, RValue argument) throws NoSuchMethodException { - if (argument instanceof LValue) { - try { - return new Function(position, Operators.class.getMethod(name, LValue.class), argument); - } catch (NoSuchMethodException ignored) { } - } - return new Function(position, Operators.class.getMethod(name, RValue.class), argument); - } - - - public static double add(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() + rhs.getValue(); - } - - public static double sub(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() - rhs.getValue(); - } - - public static double mul(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() * rhs.getValue(); - } - - public static double div(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() / rhs.getValue(); - } - - public static double mod(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() % rhs.getValue(); - } - - public static double pow(RValue lhs, RValue rhs) throws EvaluationException { - return Math.pow(lhs.getValue(), rhs.getValue()); - } - - - public static double neg(RValue x) throws EvaluationException { - return -x.getValue(); - } - - public static double not(RValue x) throws EvaluationException { - return x.getValue() > 0.0 ? 0.0 : 1.0; - } - - public static double inv(RValue x) throws EvaluationException { - return ~(long) x.getValue(); - } - - - public static double lth(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() < rhs.getValue() ? 1.0 : 0.0; - } - - public static double gth(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() > rhs.getValue() ? 1.0 : 0.0; - } - - public static double leq(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() <= rhs.getValue() ? 1.0 : 0.0; - } - - public static double geq(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() >= rhs.getValue() ? 1.0 : 0.0; - } - - - public static double equ(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() == rhs.getValue() ? 1.0 : 0.0; - } - - public static double neq(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() != rhs.getValue() ? 1.0 : 0.0; - } - - public static double near(RValue lhs, RValue rhs) throws EvaluationException { - return almostEqual2sComplement(lhs.getValue(), rhs.getValue(), 450359963L) ? 1.0 : 0.0; - //return Math.abs(lhs.invoke() - rhs.invoke()) < 1e-7 ? 1.0 : 0.0; - } - - - public static double or(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() > 0.0 || rhs.getValue() > 0.0 ? 1.0 : 0.0; - } - - public static double and(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() > 0.0 && rhs.getValue() > 0.0 ? 1.0 : 0.0; - } - - - public static double shl(RValue lhs, RValue rhs) throws EvaluationException { - return (long) lhs.getValue() << (long) rhs.getValue(); - } - - public static double shr(RValue lhs, RValue rhs) throws EvaluationException { - return (long) lhs.getValue() >> (long) rhs.getValue(); - } - - - public static double ass(LValue lhs, RValue rhs) throws EvaluationException { - return lhs.assign(rhs.getValue()); - } - - public static double aadd(LValue lhs, RValue rhs) throws EvaluationException { - return lhs.assign(lhs.getValue() + rhs.getValue()); - } - - public static double asub(LValue lhs, RValue rhs) throws EvaluationException { - return lhs.assign(lhs.getValue() - rhs.getValue()); - } - - public static double amul(LValue lhs, RValue rhs) throws EvaluationException { - return lhs.assign(lhs.getValue() * rhs.getValue()); - } - - public static double adiv(LValue lhs, RValue rhs) throws EvaluationException { - return lhs.assign(lhs.getValue() / rhs.getValue()); - } - - public static double amod(LValue lhs, RValue rhs) throws EvaluationException { - return lhs.assign(lhs.getValue() % rhs.getValue()); - } - - public static double aexp(LValue lhs, RValue rhs) throws EvaluationException { - return lhs.assign(Math.pow(lhs.getValue(), rhs.getValue())); - } - - - public static double inc(LValue x) throws EvaluationException { - return x.assign(x.getValue() + 1); - } - - public static double dec(LValue x) throws EvaluationException { - return x.assign(x.getValue() - 1); - } - - public static double postinc(LValue x) throws EvaluationException { - final double oldValue = x.getValue(); - x.assign(oldValue + 1); - return oldValue; - } - - public static double postdec(LValue x) throws EvaluationException { - final double oldValue = x.getValue(); - x.assign(oldValue - 1); - return oldValue; - } - - - private static final double[] factorials = new double[171]; - static { - double accum = 1; - factorials[0] = 1; - for (int i = 1; i < factorials.length; ++i) { - factorials[i] = accum *= i; - } - } - - public static double fac(RValue x) throws EvaluationException { - final int n = (int) x.getValue(); - - if (n < 0) { - return 0; - } - - if (n >= factorials.length) { - return Double.POSITIVE_INFINITY; - } - - return factorials[n]; - } - - // Usable AlmostEqual function, based on http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm - private static boolean almostEqual2sComplement(double A, double B, long maxUlps) { - // Make sure maxUlps is non-negative and small enough that the - // default NAN won't compare as equal to anything. - //assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); // this is for floats, not doubles - - long aLong = Double.doubleToRawLongBits(A); - // Make aLong lexicographically ordered as a twos-complement long - if (aLong < 0) aLong = 0x8000000000000000L - aLong; - - long bLong = Double.doubleToRawLongBits(B); - // Make bLong lexicographically ordered as a twos-complement long - if (bLong < 0) bLong = 0x8000000000000000L - bLong; - - final long longDiff = Math.abs(aLong - bLong); - return longDiff <= maxUlps; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.runtime; + +/** + * Contains all unary and binary operators. + * + * @author TomyLobo + */ +@SuppressWarnings("UnusedDeclaration") +public final class Operators { + public static Function getOperator(int position, String name, RValue lhs, RValue rhs) throws NoSuchMethodException { + if (lhs instanceof LValue) { + try { + return new Function(position, Operators.class.getMethod(name, LValue.class, RValue.class), lhs, rhs); + } catch (NoSuchMethodException ignored) { } + } + return new Function(position, Operators.class.getMethod(name, RValue.class, RValue.class), lhs, rhs); + } + + public static Function getOperator(int position, String name, RValue argument) throws NoSuchMethodException { + if (argument instanceof LValue) { + try { + return new Function(position, Operators.class.getMethod(name, LValue.class), argument); + } catch (NoSuchMethodException ignored) { } + } + return new Function(position, Operators.class.getMethod(name, RValue.class), argument); + } + + + public static double add(RValue lhs, RValue rhs) throws EvaluationException { + return lhs.getValue() + rhs.getValue(); + } + + public static double sub(RValue lhs, RValue rhs) throws EvaluationException { + return lhs.getValue() - rhs.getValue(); + } + + public static double mul(RValue lhs, RValue rhs) throws EvaluationException { + return lhs.getValue() * rhs.getValue(); + } + + public static double div(RValue lhs, RValue rhs) throws EvaluationException { + return lhs.getValue() / rhs.getValue(); + } + + public static double mod(RValue lhs, RValue rhs) throws EvaluationException { + return lhs.getValue() % rhs.getValue(); + } + + public static double pow(RValue lhs, RValue rhs) throws EvaluationException { + return Math.pow(lhs.getValue(), rhs.getValue()); + } + + + public static double neg(RValue x) throws EvaluationException { + return -x.getValue(); + } + + public static double not(RValue x) throws EvaluationException { + return x.getValue() > 0.0 ? 0.0 : 1.0; + } + + public static double inv(RValue x) throws EvaluationException { + return ~(long) x.getValue(); + } + + + public static double lth(RValue lhs, RValue rhs) throws EvaluationException { + return lhs.getValue() < rhs.getValue() ? 1.0 : 0.0; + } + + public static double gth(RValue lhs, RValue rhs) throws EvaluationException { + return lhs.getValue() > rhs.getValue() ? 1.0 : 0.0; + } + + public static double leq(RValue lhs, RValue rhs) throws EvaluationException { + return lhs.getValue() <= rhs.getValue() ? 1.0 : 0.0; + } + + public static double geq(RValue lhs, RValue rhs) throws EvaluationException { + return lhs.getValue() >= rhs.getValue() ? 1.0 : 0.0; + } + + + public static double equ(RValue lhs, RValue rhs) throws EvaluationException { + return lhs.getValue() == rhs.getValue() ? 1.0 : 0.0; + } + + public static double neq(RValue lhs, RValue rhs) throws EvaluationException { + return lhs.getValue() != rhs.getValue() ? 1.0 : 0.0; + } + + public static double near(RValue lhs, RValue rhs) throws EvaluationException { + return almostEqual2sComplement(lhs.getValue(), rhs.getValue(), 450359963L) ? 1.0 : 0.0; + //return Math.abs(lhs.invoke() - rhs.invoke()) < 1e-7 ? 1.0 : 0.0; + } + + + public static double or(RValue lhs, RValue rhs) throws EvaluationException { + return lhs.getValue() > 0.0 || rhs.getValue() > 0.0 ? 1.0 : 0.0; + } + + public static double and(RValue lhs, RValue rhs) throws EvaluationException { + return lhs.getValue() > 0.0 && rhs.getValue() > 0.0 ? 1.0 : 0.0; + } + + + public static double shl(RValue lhs, RValue rhs) throws EvaluationException { + return (long) lhs.getValue() << (long) rhs.getValue(); + } + + public static double shr(RValue lhs, RValue rhs) throws EvaluationException { + return (long) lhs.getValue() >> (long) rhs.getValue(); + } + + + public static double ass(LValue lhs, RValue rhs) throws EvaluationException { + return lhs.assign(rhs.getValue()); + } + + public static double aadd(LValue lhs, RValue rhs) throws EvaluationException { + return lhs.assign(lhs.getValue() + rhs.getValue()); + } + + public static double asub(LValue lhs, RValue rhs) throws EvaluationException { + return lhs.assign(lhs.getValue() - rhs.getValue()); + } + + public static double amul(LValue lhs, RValue rhs) throws EvaluationException { + return lhs.assign(lhs.getValue() * rhs.getValue()); + } + + public static double adiv(LValue lhs, RValue rhs) throws EvaluationException { + return lhs.assign(lhs.getValue() / rhs.getValue()); + } + + public static double amod(LValue lhs, RValue rhs) throws EvaluationException { + return lhs.assign(lhs.getValue() % rhs.getValue()); + } + + public static double aexp(LValue lhs, RValue rhs) throws EvaluationException { + return lhs.assign(Math.pow(lhs.getValue(), rhs.getValue())); + } + + + public static double inc(LValue x) throws EvaluationException { + return x.assign(x.getValue() + 1); + } + + public static double dec(LValue x) throws EvaluationException { + return x.assign(x.getValue() - 1); + } + + public static double postinc(LValue x) throws EvaluationException { + final double oldValue = x.getValue(); + x.assign(oldValue + 1); + return oldValue; + } + + public static double postdec(LValue x) throws EvaluationException { + final double oldValue = x.getValue(); + x.assign(oldValue - 1); + return oldValue; + } + + + private static final double[] factorials = new double[171]; + static { + double accum = 1; + factorials[0] = 1; + for (int i = 1; i < factorials.length; ++i) { + factorials[i] = accum *= i; + } + } + + public static double fac(RValue x) throws EvaluationException { + final int n = (int) x.getValue(); + + if (n < 0) { + return 0; + } + + if (n >= factorials.length) { + return Double.POSITIVE_INFINITY; + } + + return factorials[n]; + } + + // Usable AlmostEqual function, based on http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm + private static boolean almostEqual2sComplement(double A, double B, long maxUlps) { + // Make sure maxUlps is non-negative and small enough that the + // default NAN won't compare as equal to anything. + //assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); // this is for floats, not doubles + + long aLong = Double.doubleToRawLongBits(A); + // Make aLong lexicographically ordered as a twos-complement long + if (aLong < 0) aLong = 0x8000000000000000L - aLong; + + long bLong = Double.doubleToRawLongBits(B); + // Make bLong lexicographically ordered as a twos-complement long + if (bLong < 0) bLong = 0x8000000000000000L - bLong; + + final long longDiff = Math.abs(aLong - bLong); + return longDiff <= maxUlps; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/runtime/RValue.java b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/RValue.java similarity index 81% rename from src/main/java/com/sk89q/worldedit/expression/runtime/RValue.java rename to src/main/java/com/sk89q/worldedit/internal/expression/runtime/RValue.java index 863577d5b..83077162e 100644 --- a/src/main/java/com/sk89q/worldedit/expression/runtime/RValue.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/RValue.java @@ -1,37 +1,37 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.runtime; - -import com.sk89q.worldedit.expression.Expression; -import com.sk89q.worldedit.expression.Identifiable; -import com.sk89q.worldedit.expression.parser.ParserException; - -/** - * A value that can be used on the right side of an assignment. - * - * @author TomyLobo - */ -public interface RValue extends Identifiable { - public double getValue() throws EvaluationException; - - public RValue optimize() throws EvaluationException; - - public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException; -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.runtime; + +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.Identifiable; +import com.sk89q.worldedit.internal.expression.parser.ParserException; + +/** + * A value that can be used on the right side of an assignment. + * + * @author TomyLobo + */ +public interface RValue extends Identifiable { + public double getValue() throws EvaluationException; + + public RValue optimize() throws EvaluationException; + + public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException; +} diff --git a/src/main/java/com/sk89q/worldedit/expression/runtime/Return.java b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Return.java similarity index 86% rename from src/main/java/com/sk89q/worldedit/expression/runtime/Return.java rename to src/main/java/com/sk89q/worldedit/internal/expression/runtime/Return.java index fb3e42336..d02fc2488 100644 --- a/src/main/java/com/sk89q/worldedit/expression/runtime/Return.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Return.java @@ -1,60 +1,60 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.runtime; - -import com.sk89q.worldedit.expression.Expression; -import com.sk89q.worldedit.expression.parser.ParserException; - -/** - * A return statement. - * - * @author TomyLobo - */ -public class Return extends Node { - RValue value; - - public Return(int position, RValue value) { - super(position); - - this.value = value; - } - - @Override - public double getValue() throws EvaluationException { - throw new ReturnException(value.getValue()); - } - - @Override - public char id() { - return 'r'; - } - - @Override - public String toString() { - return "return " + value; - } - - @Override - public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { - value = value.bindVariables(expression, false); - - return this; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.runtime; + +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.parser.ParserException; + +/** + * A return statement. + * + * @author TomyLobo + */ +public class Return extends Node { + RValue value; + + public Return(int position, RValue value) { + super(position); + + this.value = value; + } + + @Override + public double getValue() throws EvaluationException { + throw new ReturnException(value.getValue()); + } + + @Override + public char id() { + return 'r'; + } + + @Override + public String toString() { + return "return " + value; + } + + @Override + public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { + value = value.bindVariables(expression, false); + + return this; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/runtime/ReturnException.java b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/ReturnException.java similarity index 84% rename from src/main/java/com/sk89q/worldedit/expression/runtime/ReturnException.java rename to src/main/java/com/sk89q/worldedit/internal/expression/runtime/ReturnException.java index 7f91a430e..2635ad619 100644 --- a/src/main/java/com/sk89q/worldedit/expression/runtime/ReturnException.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/ReturnException.java @@ -1,42 +1,42 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.runtime; - -/** - * Thrown when a return statement is encountered. - * {@link com.sk89q.worldedit.expression.Expression#evaluate} catches this exception and returns the enclosed value. - * - * @author TomyLobo - */ -public class ReturnException extends EvaluationException { - private static final long serialVersionUID = 1L; - - final double value; - - public ReturnException(double value) { - super(-1); - - this.value = value; - } - - public double getValue() { - return value; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.runtime; + +/** + * Thrown when a return statement is encountered. + * {@link com.sk89q.worldedit.internal.expression.Expression#evaluate} catches this exception and returns the enclosed value. + * + * @author TomyLobo + */ +public class ReturnException extends EvaluationException { + private static final long serialVersionUID = 1L; + + final double value; + + public ReturnException(double value) { + super(-1); + + this.value = value; + } + + public double getValue() { + return value; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/runtime/Sequence.java b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Sequence.java similarity index 91% rename from src/main/java/com/sk89q/worldedit/expression/runtime/Sequence.java rename to src/main/java/com/sk89q/worldedit/internal/expression/runtime/Sequence.java index 88edf50c2..a8f06d178 100644 --- a/src/main/java/com/sk89q/worldedit/expression/runtime/Sequence.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Sequence.java @@ -1,109 +1,109 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.runtime; - -import java.util.ArrayList; -import java.util.List; - -import com.sk89q.worldedit.expression.Expression; -import com.sk89q.worldedit.expression.parser.ParserException; - -/** - * A sequence of operations, usually separated by semicolons in the input stream. - * - * @author TomyLobo - */ -public class Sequence extends Node { - final RValue[] sequence; - - public Sequence(int position, RValue... sequence) { - super(position); - - this.sequence = sequence; - } - - @Override - public char id() { - return 's'; - } - - @Override - public double getValue() throws EvaluationException { - double ret = 0; - for (RValue invokable : sequence) { - ret = invokable.getValue(); - } - return ret; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder("seq("); - boolean first = true; - for (RValue invokable : sequence) { - if (!first) { - sb.append(", "); - } - sb.append(invokable); - first = false; - } - - return sb.append(')').toString(); - } - - @Override - public RValue optimize() throws EvaluationException { - final List newSequence = new ArrayList(); - - RValue droppedLast = null; - for (RValue invokable : sequence) { - droppedLast = null; - invokable = invokable.optimize(); - if (invokable instanceof Sequence) { - for (RValue subInvokable : ((Sequence) invokable).sequence) { - newSequence.add(subInvokable); - } - } else if (invokable instanceof Constant) { - droppedLast = invokable; - } else { - newSequence.add(invokable); - } - } - - if (droppedLast != null) { - newSequence.add(droppedLast); - } - - if (newSequence.size() == 1) { - return newSequence.get(0); - } - - return new Sequence(getPosition(), newSequence.toArray(new RValue[newSequence.size()])); - } - - @Override - public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { - for (int i = 0; i < sequence.length; ++i) { - sequence[i] = sequence[i].bindVariables(expression, false); - } - - return this; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.runtime; + +import java.util.ArrayList; +import java.util.List; + +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.parser.ParserException; + +/** + * A sequence of operations, usually separated by semicolons in the input stream. + * + * @author TomyLobo + */ +public class Sequence extends Node { + final RValue[] sequence; + + public Sequence(int position, RValue... sequence) { + super(position); + + this.sequence = sequence; + } + + @Override + public char id() { + return 's'; + } + + @Override + public double getValue() throws EvaluationException { + double ret = 0; + for (RValue invokable : sequence) { + ret = invokable.getValue(); + } + return ret; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("seq("); + boolean first = true; + for (RValue invokable : sequence) { + if (!first) { + sb.append(", "); + } + sb.append(invokable); + first = false; + } + + return sb.append(')').toString(); + } + + @Override + public RValue optimize() throws EvaluationException { + final List newSequence = new ArrayList(); + + RValue droppedLast = null; + for (RValue invokable : sequence) { + droppedLast = null; + invokable = invokable.optimize(); + if (invokable instanceof Sequence) { + for (RValue subInvokable : ((Sequence) invokable).sequence) { + newSequence.add(subInvokable); + } + } else if (invokable instanceof Constant) { + droppedLast = invokable; + } else { + newSequence.add(invokable); + } + } + + if (droppedLast != null) { + newSequence.add(droppedLast); + } + + if (newSequence.size() == 1) { + return newSequence.get(0); + } + + return new Sequence(getPosition(), newSequence.toArray(new RValue[newSequence.size()])); + } + + @Override + public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { + for (int i = 0; i < sequence.length; ++i) { + sequence[i] = sequence[i].bindVariables(expression, false); + } + + return this; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/runtime/SimpleFor.java b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/SimpleFor.java similarity index 91% rename from src/main/java/com/sk89q/worldedit/expression/runtime/SimpleFor.java rename to src/main/java/com/sk89q/worldedit/internal/expression/runtime/SimpleFor.java index 801e9709d..51eadc06e 100644 --- a/src/main/java/com/sk89q/worldedit/expression/runtime/SimpleFor.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/SimpleFor.java @@ -1,101 +1,101 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.runtime; - -import com.sk89q.worldedit.expression.Expression; -import com.sk89q.worldedit.expression.parser.ParserException; - -/** - * A simple-style for loop. - * - * @author TomyLobo - */ -public class SimpleFor extends Node { - LValue counter; - RValue first; - RValue last; - RValue body; - - public SimpleFor(int position, LValue counter, RValue first, RValue last, RValue body) { - super(position); - - this.counter = counter; - this.first = first; - this.last = last; - this.body = body; - } - - @Override - public double getValue() throws EvaluationException { - int iterations = 0; - double ret = 0.0; - - double firstValue = first.getValue(); - double lastValue = last.getValue(); - - for (double i = firstValue; i <= lastValue; ++i) { - if (iterations > 256) { - throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations."); - } - ++iterations; - - try { - counter.assign(i); - ret = body.getValue(); - } catch (BreakException e) { - if (e.doContinue) { - //noinspection UnnecessaryContinue - continue; - } else { - break; - } - } - } - - return ret; - } - - @Override - public char id() { - return 'S'; - } - - @Override - public String toString() { - return "for (" + counter + " = " + first + ", " + last + ") { " + body + " }"; - } - - @Override - public RValue optimize() throws EvaluationException { - // TODO: unroll small loops into Sequences - - return new SimpleFor(getPosition(), (LValue) counter.optimize(), first.optimize(), last.optimize(), body.optimize()); - } - - @Override - public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { - counter = counter.bindVariables(expression, true); - first = first.bindVariables(expression, false); - last = last.bindVariables(expression, false); - body = body.bindVariables(expression, false); - - return this; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.runtime; + +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.parser.ParserException; + +/** + * A simple-style for loop. + * + * @author TomyLobo + */ +public class SimpleFor extends Node { + LValue counter; + RValue first; + RValue last; + RValue body; + + public SimpleFor(int position, LValue counter, RValue first, RValue last, RValue body) { + super(position); + + this.counter = counter; + this.first = first; + this.last = last; + this.body = body; + } + + @Override + public double getValue() throws EvaluationException { + int iterations = 0; + double ret = 0.0; + + double firstValue = first.getValue(); + double lastValue = last.getValue(); + + for (double i = firstValue; i <= lastValue; ++i) { + if (iterations > 256) { + throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations."); + } + ++iterations; + + try { + counter.assign(i); + ret = body.getValue(); + } catch (BreakException e) { + if (e.doContinue) { + //noinspection UnnecessaryContinue + continue; + } else { + break; + } + } + } + + return ret; + } + + @Override + public char id() { + return 'S'; + } + + @Override + public String toString() { + return "for (" + counter + " = " + first + ", " + last + ") { " + body + " }"; + } + + @Override + public RValue optimize() throws EvaluationException { + // TODO: unroll small loops into Sequences + + return new SimpleFor(getPosition(), (LValue) counter.optimize(), first.optimize(), last.optimize(), body.optimize()); + } + + @Override + public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { + counter = counter.bindVariables(expression, true); + first = first.bindVariables(expression, false); + last = last.bindVariables(expression, false); + body = body.bindVariables(expression, false); + + return this; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/runtime/Switch.java b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Switch.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/expression/runtime/Switch.java rename to src/main/java/com/sk89q/worldedit/internal/expression/runtime/Switch.java index cdf259038..f7b8a3393 100644 --- a/src/main/java/com/sk89q/worldedit/expression/runtime/Switch.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Switch.java @@ -1,208 +1,208 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.runtime; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import com.sk89q.worldedit.expression.Expression; -import com.sk89q.worldedit.expression.parser.ParserException; - -/** - * A switch/case construct. - * - * @author TomyLobo - */ -public class Switch extends Node implements RValue { - private RValue parameter; - private final Map valueMap; - private final RValue[] caseStatements; - private RValue defaultCase; - - public Switch(int position, RValue parameter, List values, List caseStatements, RValue defaultCase) { - this(position, parameter, invertList(values), caseStatements, defaultCase); - - } - - private static Map invertList(List values) { - Map valueMap = new HashMap(); - for (int i = 0; i < values.size(); ++i) { - valueMap.put(values.get(i), i); - } - return valueMap; - } - - private Switch(int position, RValue parameter, Map valueMap, List caseStatements, RValue defaultCase) { - super(position); - - this.parameter = parameter; - this.valueMap = valueMap; - this.caseStatements = caseStatements.toArray(new RValue[caseStatements.size()]); - this.defaultCase = defaultCase; - } - - @Override - public char id() { - return 'W'; - } - - @Override - public double getValue() throws EvaluationException { - final double parameter = this.parameter.getValue(); - - try { - double ret = 0.0; - - final Integer index = valueMap.get(parameter); - if (index != null) { - for (int i = index; i < caseStatements.length; ++i) { - ret = caseStatements[i].getValue(); - } - } - - return defaultCase == null ? ret : defaultCase.getValue(); - } catch (BreakException e) { - if (e.doContinue) throw e; - - return 0.0; - } - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder(); - - sb.append("switch ("); - sb.append(parameter); - sb.append(") { "); - - for (int i = 0; i < caseStatements.length; ++i) { - RValue caseStatement = caseStatements[i]; - sb.append("case "); - for (Entry entry : valueMap.entrySet()) { - if (entry.getValue() == i) { - sb.append(entry.getKey()); - break; - } - } - sb.append(": "); - sb.append(caseStatement); - sb.append(' '); - } - - if (defaultCase != null) { - sb.append("default: "); - sb.append(defaultCase); - sb.append(' '); - } - - sb.append("}"); - - return sb.toString(); - } - - @Override - public RValue optimize() throws EvaluationException { - final RValue optimizedParameter = parameter.optimize(); - final List newSequence = new ArrayList(); - - if (optimizedParameter instanceof Constant) { - final double parameter = optimizedParameter.getValue(); - - final Integer index = valueMap.get(parameter); - if (index == null) { - return defaultCase == null ? new Constant(getPosition(), 0.0) : defaultCase.optimize(); - } - - boolean breakDetected = false; - for (int i = index; i < caseStatements.length && !breakDetected ; ++i) { - final RValue invokable = caseStatements[i].optimize(); - - if (invokable instanceof Sequence) { - for (RValue subInvokable : ((Sequence) invokable).sequence) { - if (subInvokable instanceof Break) { - breakDetected = true; - break; - } - - newSequence.add(subInvokable); - } - } else { - newSequence.add(invokable); - } - } - - if (defaultCase != null && !breakDetected) { - final RValue invokable = defaultCase.optimize(); - - if (invokable instanceof Sequence) { - Collections.addAll(newSequence, ((Sequence) invokable).sequence); - } else { - newSequence.add(invokable); - } - } - - return new Switch(getPosition(), optimizedParameter, Collections.singletonMap(parameter, 0), newSequence, null); - } - - final Map newValueMap = new HashMap(); - - Map backMap = new HashMap(); - for (Entry entry : valueMap.entrySet()) { - backMap.put(entry.getValue(), entry.getKey()); - } - - for (int i = 0; i < caseStatements.length; ++i) { - final RValue invokable = caseStatements[i].optimize(); - - final Double caseValue = backMap.get(i); - if (caseValue != null) { - newValueMap.put(caseValue, newSequence.size()); - } - - if (invokable instanceof Sequence) { - for (RValue subInvokable : ((Sequence) invokable).sequence) { - newSequence.add(subInvokable); - } - } else { - newSequence.add(invokable); - } - } - - return new Switch(getPosition(), optimizedParameter, newValueMap, newSequence, defaultCase.optimize()); - } - - @Override - public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { - parameter = parameter.bindVariables(expression, false); - - for (int i = 0; i < caseStatements.length; ++i) { - caseStatements[i] = caseStatements[i].bindVariables(expression, false); - } - - defaultCase = defaultCase.bindVariables(expression, false); - - return this; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.runtime; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.parser.ParserException; + +/** + * A switch/case construct. + * + * @author TomyLobo + */ +public class Switch extends Node implements RValue { + private RValue parameter; + private final Map valueMap; + private final RValue[] caseStatements; + private RValue defaultCase; + + public Switch(int position, RValue parameter, List values, List caseStatements, RValue defaultCase) { + this(position, parameter, invertList(values), caseStatements, defaultCase); + + } + + private static Map invertList(List values) { + Map valueMap = new HashMap(); + for (int i = 0; i < values.size(); ++i) { + valueMap.put(values.get(i), i); + } + return valueMap; + } + + private Switch(int position, RValue parameter, Map valueMap, List caseStatements, RValue defaultCase) { + super(position); + + this.parameter = parameter; + this.valueMap = valueMap; + this.caseStatements = caseStatements.toArray(new RValue[caseStatements.size()]); + this.defaultCase = defaultCase; + } + + @Override + public char id() { + return 'W'; + } + + @Override + public double getValue() throws EvaluationException { + final double parameter = this.parameter.getValue(); + + try { + double ret = 0.0; + + final Integer index = valueMap.get(parameter); + if (index != null) { + for (int i = index; i < caseStatements.length; ++i) { + ret = caseStatements[i].getValue(); + } + } + + return defaultCase == null ? ret : defaultCase.getValue(); + } catch (BreakException e) { + if (e.doContinue) throw e; + + return 0.0; + } + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + + sb.append("switch ("); + sb.append(parameter); + sb.append(") { "); + + for (int i = 0; i < caseStatements.length; ++i) { + RValue caseStatement = caseStatements[i]; + sb.append("case "); + for (Entry entry : valueMap.entrySet()) { + if (entry.getValue() == i) { + sb.append(entry.getKey()); + break; + } + } + sb.append(": "); + sb.append(caseStatement); + sb.append(' '); + } + + if (defaultCase != null) { + sb.append("default: "); + sb.append(defaultCase); + sb.append(' '); + } + + sb.append("}"); + + return sb.toString(); + } + + @Override + public RValue optimize() throws EvaluationException { + final RValue optimizedParameter = parameter.optimize(); + final List newSequence = new ArrayList(); + + if (optimizedParameter instanceof Constant) { + final double parameter = optimizedParameter.getValue(); + + final Integer index = valueMap.get(parameter); + if (index == null) { + return defaultCase == null ? new Constant(getPosition(), 0.0) : defaultCase.optimize(); + } + + boolean breakDetected = false; + for (int i = index; i < caseStatements.length && !breakDetected ; ++i) { + final RValue invokable = caseStatements[i].optimize(); + + if (invokable instanceof Sequence) { + for (RValue subInvokable : ((Sequence) invokable).sequence) { + if (subInvokable instanceof Break) { + breakDetected = true; + break; + } + + newSequence.add(subInvokable); + } + } else { + newSequence.add(invokable); + } + } + + if (defaultCase != null && !breakDetected) { + final RValue invokable = defaultCase.optimize(); + + if (invokable instanceof Sequence) { + Collections.addAll(newSequence, ((Sequence) invokable).sequence); + } else { + newSequence.add(invokable); + } + } + + return new Switch(getPosition(), optimizedParameter, Collections.singletonMap(parameter, 0), newSequence, null); + } + + final Map newValueMap = new HashMap(); + + Map backMap = new HashMap(); + for (Entry entry : valueMap.entrySet()) { + backMap.put(entry.getValue(), entry.getKey()); + } + + for (int i = 0; i < caseStatements.length; ++i) { + final RValue invokable = caseStatements[i].optimize(); + + final Double caseValue = backMap.get(i); + if (caseValue != null) { + newValueMap.put(caseValue, newSequence.size()); + } + + if (invokable instanceof Sequence) { + for (RValue subInvokable : ((Sequence) invokable).sequence) { + newSequence.add(subInvokable); + } + } else { + newSequence.add(invokable); + } + } + + return new Switch(getPosition(), optimizedParameter, newValueMap, newSequence, defaultCase.optimize()); + } + + @Override + public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { + parameter = parameter.bindVariables(expression, false); + + for (int i = 0; i < caseStatements.length; ++i) { + caseStatements[i] = caseStatements[i].bindVariables(expression, false); + } + + defaultCase = defaultCase.bindVariables(expression, false); + + return this; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/runtime/Variable.java b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Variable.java similarity index 87% rename from src/main/java/com/sk89q/worldedit/expression/runtime/Variable.java rename to src/main/java/com/sk89q/worldedit/internal/expression/runtime/Variable.java index 22477fdeb..da405d769 100644 --- a/src/main/java/com/sk89q/worldedit/expression/runtime/Variable.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Variable.java @@ -1,67 +1,67 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.runtime; - -import com.sk89q.worldedit.expression.Expression; -import com.sk89q.worldedit.expression.parser.ParserException; - -/** - * A variable. - * - * @author TomyLobo - */ -public final class Variable extends Node implements LValue { - public double value; - - public Variable(double value) { - super(-1); - this.value = value; - } - - @Override - public double getValue() { - return value; - } - - @Override - public String toString() { - return "var"; - } - - @Override - public char id() { - return 'v'; - } - - @Override - public double assign(double value) { - return this.value = value; - } - - @Override - public LValue optimize() throws EvaluationException { - return this; - } - - @Override - public LValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { - return this; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.runtime; + +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.parser.ParserException; + +/** + * A variable. + * + * @author TomyLobo + */ +public final class Variable extends Node implements LValue { + public double value; + + public Variable(double value) { + super(-1); + this.value = value; + } + + @Override + public double getValue() { + return value; + } + + @Override + public String toString() { + return "var"; + } + + @Override + public char id() { + return 'v'; + } + + @Override + public double assign(double value) { + return this.value = value; + } + + @Override + public LValue optimize() throws EvaluationException { + return this; + } + + @Override + public LValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { + return this; + } +} diff --git a/src/main/java/com/sk89q/worldedit/expression/runtime/While.java b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/While.java similarity index 92% rename from src/main/java/com/sk89q/worldedit/expression/runtime/While.java rename to src/main/java/com/sk89q/worldedit/internal/expression/runtime/While.java index f68dcb660..592a56067 100644 --- a/src/main/java/com/sk89q/worldedit/expression/runtime/While.java +++ b/src/main/java/com/sk89q/worldedit/internal/expression/runtime/While.java @@ -1,127 +1,127 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.expression.runtime; - -import com.sk89q.worldedit.expression.Expression; -import com.sk89q.worldedit.expression.parser.ParserException; - -/** - * A while loop. - * - * @author TomyLobo - */ -public class While extends Node { - RValue condition; - RValue body; - boolean footChecked; - - public While(int position, RValue condition, RValue body, boolean footChecked) { - super(position); - - this.condition = condition; - this.body = body; - this.footChecked = footChecked; - } - - @Override - public double getValue() throws EvaluationException { - int iterations = 0; - double ret = 0.0; - - if (footChecked) { - do { - if (iterations > 256) { - throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations."); - } - ++iterations; - - try { - ret = body.getValue(); - } catch (BreakException e) { - if (e.doContinue) { - continue; - } else { - break; - } - } - } while (condition.getValue() > 0.0); - } else { - while (condition.getValue() > 0.0) { - if (iterations > 256) { - throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations."); - } - ++iterations; - - try { - ret = body.getValue(); - } catch (BreakException e) { - if (e.doContinue) { - //noinspection UnnecessaryContinue - continue; - } else { - break; - } - } - } - } - - return ret; - } - - @Override - public char id() { - return 'w'; - } - - @Override - public String toString() { - if (footChecked) { - return "do { " + body + " } while (" + condition + ")"; - } else { - return "while (" + condition + ") { " + body + " }"; - } - } - - @Override - public RValue optimize() throws EvaluationException { - final RValue newCondition = condition.optimize(); - - if (newCondition instanceof Constant && newCondition.getValue() <= 0) { - // If the condition is always false, the loop can be flattened. - if (footChecked) { - // Foot-checked loops run at least once. - return body.optimize(); - } else { - // Loops that never run always return 0.0. - return new Constant(getPosition(), 0.0); - } - } - - return new While(getPosition(), newCondition, body.optimize(), footChecked); - } - - @Override - public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { - condition = condition.bindVariables(expression, false); - body = body.bindVariables(expression, false); - - return this; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.internal.expression.runtime; + +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.parser.ParserException; + +/** + * A while loop. + * + * @author TomyLobo + */ +public class While extends Node { + RValue condition; + RValue body; + boolean footChecked; + + public While(int position, RValue condition, RValue body, boolean footChecked) { + super(position); + + this.condition = condition; + this.body = body; + this.footChecked = footChecked; + } + + @Override + public double getValue() throws EvaluationException { + int iterations = 0; + double ret = 0.0; + + if (footChecked) { + do { + if (iterations > 256) { + throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations."); + } + ++iterations; + + try { + ret = body.getValue(); + } catch (BreakException e) { + if (e.doContinue) { + continue; + } else { + break; + } + } + } while (condition.getValue() > 0.0); + } else { + while (condition.getValue() > 0.0) { + if (iterations > 256) { + throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations."); + } + ++iterations; + + try { + ret = body.getValue(); + } catch (BreakException e) { + if (e.doContinue) { + //noinspection UnnecessaryContinue + continue; + } else { + break; + } + } + } + } + + return ret; + } + + @Override + public char id() { + return 'w'; + } + + @Override + public String toString() { + if (footChecked) { + return "do { " + body + " } while (" + condition + ")"; + } else { + return "while (" + condition + ") { " + body + " }"; + } + } + + @Override + public RValue optimize() throws EvaluationException { + final RValue newCondition = condition.optimize(); + + if (newCondition instanceof Constant && newCondition.getValue() <= 0) { + // If the condition is always false, the loop can be flattened. + if (footChecked) { + // Foot-checked loops run at least once. + return body.optimize(); + } else { + // Loops that never run always return 0.0. + return new Constant(getPosition(), 0.0); + } + } + + return new While(getPosition(), newCondition, body.optimize(), footChecked); + } + + @Override + public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { + condition = condition.bindVariables(expression, false); + body = body.bindVariables(expression, false); + + return this; + } +} diff --git a/src/main/java/com/sk89q/worldedit/internal/registry/AbstractRegistry.java b/src/main/java/com/sk89q/worldedit/internal/registry/AbstractRegistry.java new file mode 100644 index 000000000..6e79efe31 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/registry/AbstractRegistry.java @@ -0,0 +1,67 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.internal.registry; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.NoMatchException; + +import java.util.ArrayList; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An abstract implementation of a registry for internal usage. + * + * @param the element that the registry returns + */ +@SuppressWarnings("ProtectedField") +public abstract class AbstractRegistry { + + protected final WorldEdit worldEdit; + protected final List> parsers = new ArrayList>(); + + /** + * Create a new registry. + * + * @param worldEdit the WorldEdit instance + */ + protected AbstractRegistry(WorldEdit worldEdit) { + checkNotNull(worldEdit); + this.worldEdit = worldEdit; + } + + public E parseFromInput(String input, ParserContext context) throws InputParseException { + E match; + + for (InputParser parser : parsers) { + match = parser.parseFromInput(input, context); + + if (match != null) { + return match; + } + } + + throw new NoMatchException("No match for '" + input + "'"); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java b/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java new file mode 100644 index 000000000..5dd6a13e2 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java @@ -0,0 +1,42 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.internal.registry; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.input.InputParseException; + +/** + * Input parser interface for {@link AbstractRegistry}. + * + * @param the element + */ +@SuppressWarnings("ProtectedField") +public abstract class InputParser { + + protected final WorldEdit worldEdit; + + protected InputParser(WorldEdit worldEdit) { + this.worldEdit = worldEdit; + } + + public abstract E parseFromInput(String input, ParserContext context) throws InputParseException; + +} diff --git a/src/main/java/com/sk89q/worldedit/dev/DocumentationPrinter.java b/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java similarity index 87% rename from src/main/java/com/sk89q/worldedit/dev/DocumentationPrinter.java rename to src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java index 0a738d34c..cfacec6a6 100644 --- a/src/main/java/com/sk89q/worldedit/dev/DocumentationPrinter.java +++ b/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java @@ -1,209 +1,209 @@ -// $Id$ -/* - * WorldEditLibrary - * Copyright (C) 2010 sk89q 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.dev; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.NestedCommand; -import com.sk89q.worldedit.commands.BiomeCommands; -import com.sk89q.worldedit.commands.ChunkCommands; -import com.sk89q.worldedit.commands.ClipboardCommands; -import com.sk89q.worldedit.commands.GeneralCommands; -import com.sk89q.worldedit.commands.GenerationCommands; -import com.sk89q.worldedit.commands.HistoryCommands; -import com.sk89q.worldedit.commands.NavigationCommands; -import com.sk89q.worldedit.commands.RegionCommands; -import com.sk89q.worldedit.commands.ScriptingCommands; -import com.sk89q.worldedit.commands.SelectionCommands; -import com.sk89q.worldedit.commands.SnapshotUtilCommands; -import com.sk89q.worldedit.commands.ToolCommands; -import com.sk89q.worldedit.commands.ToolUtilCommands; -import com.sk89q.worldedit.commands.UtilityCommands; - -public class DocumentationPrinter { - public static void main(String[] args) throws IOException { - File commandsDir = new File(args[0]); - - List> commandClasses = getCommandClasses(commandsDir); - - System.out.println("Writing permissions wiki table..."); - writePermissionsWikiTable(commandClasses); - System.out.println("Writing Bukkit plugin.yml..."); - writeBukkitYAML(); - - System.out.println("Done!"); - } - - private static List> getCommandClasses(File dir) { - List> classes = new ArrayList>(); - - classes.add(BiomeCommands.class); - classes.add(ChunkCommands.class); - classes.add(ClipboardCommands.class); - classes.add(GeneralCommands.class); - classes.add(GenerationCommands.class); - classes.add(HistoryCommands.class); - classes.add(NavigationCommands.class); - classes.add(RegionCommands.class); - classes.add(ScriptingCommands.class); - classes.add(SelectionCommands.class); - classes.add(SnapshotUtilCommands.class); - classes.add(ToolUtilCommands.class); - classes.add(ToolCommands.class); - classes.add(UtilityCommands.class); - - /*for (File f : dir.listFiles()) { - if (!f.getName().matches("^.*\\.java$")) { - continue; - } - - String className = "com.sk89q.worldedit.commands." - + f.getName().substring(0, f.getName().lastIndexOf(".")); - - Class cls; - try { - cls = Class.forName(className, true, - Thread.currentThread().getContextClassLoader()); - } catch (ClassNotFoundException e) { - continue; - } - - classes.add(cls); - }*/ - - return classes; - } - - private static void writePermissionsWikiTable(List> commandClasses) - throws IOException { - FileOutputStream stream = null; - try { - stream = new FileOutputStream("wiki_permissions.txt"); - PrintStream print = new PrintStream(stream); - _writePermissionsWikiTable(print, commandClasses, "/"); - } finally { - if (stream != null) { - stream.close(); - } - } - } - - private static void _writePermissionsWikiTable(PrintStream stream, - List> commandClasses, String prefix) { - - for (Class cls : commandClasses) { - for (Method method : cls.getMethods()) { - if (!method.isAnnotationPresent(Command.class)) { - continue; - } - - Command cmd = method.getAnnotation(Command.class); - - stream.println("|-"); - stream.print("| " + prefix + cmd.aliases()[0]); - stream.print(" || "); - - if (method.isAnnotationPresent(CommandPermissions.class)) { - CommandPermissions perms = - method.getAnnotation(CommandPermissions.class); - - String[] permKeys = perms.value(); - for (int i = 0; i < permKeys.length; ++i) { - if (i > 0) { - stream.print(", "); - } - stream.print(permKeys[i]); - } - } - - stream.print(" || "); - - boolean firstAlias = true; - if (cmd.aliases().length != 0) { - for (String alias : cmd.aliases()) { - if (!firstAlias) stream.print("
"); - stream.print(prefix + alias); - firstAlias = false; - } - } - - stream.print(" || "); - - if (cmd.flags() != null && !cmd.flags().equals("")) { - stream.print(cmd.flags()); - } - - stream.print(" || "); - - if (cmd.desc() != null && !cmd.desc().equals("")) { - stream.print(cmd.desc()); - } - - stream.println(); - - if (method.isAnnotationPresent(NestedCommand.class)) { - NestedCommand nested = - method.getAnnotation(NestedCommand.class); - - Class[] nestedClasses = nested.value(); - _writePermissionsWikiTable(stream, - Arrays.asList(nestedClasses), - prefix + cmd.aliases()[0] + " "); - } - } - } - } - - private static void writeBukkitYAML() - throws IOException { - FileOutputStream stream = null; - try { - stream = new FileOutputStream("plugin.yml"); - PrintStream print = new PrintStream(stream); - _writeBukkitYAML(print); - } finally { - if (stream != null) { - stream.close(); - } - } - } - - private static void _writeBukkitYAML(PrintStream stream) { - - stream.println("name: WorldEdit"); - stream.println("main: com.sk89q.worldedit.bukkit.WorldEditPlugin"); - stream.println("version: ${project.version}"); - stream.println("softdepend: [Spout] #hack to fix trove errors"); - - stream.println(); - stream.println(); - stream.println("# Permissions aren't here. Read http://wiki.sk89q.com/wiki/WEPIF/DinnerPerms"); - stream.println("# for how WorldEdit permissions actually work."); - } -} +// $Id$ +/* + * WorldEditLibrary + * Copyright (C) 2010 sk89q 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.internal.util; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import com.sk89q.minecraft.util.commands.Command; +import com.sk89q.minecraft.util.commands.CommandPermissions; +import com.sk89q.minecraft.util.commands.NestedCommand; +import com.sk89q.worldedit.command.BiomeCommands; +import com.sk89q.worldedit.command.ChunkCommands; +import com.sk89q.worldedit.command.ClipboardCommands; +import com.sk89q.worldedit.command.GeneralCommands; +import com.sk89q.worldedit.command.GenerationCommands; +import com.sk89q.worldedit.command.HistoryCommands; +import com.sk89q.worldedit.command.NavigationCommands; +import com.sk89q.worldedit.command.RegionCommands; +import com.sk89q.worldedit.command.ScriptingCommands; +import com.sk89q.worldedit.command.SelectionCommands; +import com.sk89q.worldedit.command.SnapshotUtilCommands; +import com.sk89q.worldedit.command.ToolCommands; +import com.sk89q.worldedit.command.ToolUtilCommands; +import com.sk89q.worldedit.command.UtilityCommands; + +public class DocumentationPrinter { + public static void main(String[] args) throws IOException { + File commandsDir = new File(args[0]); + + List> commandClasses = getCommandClasses(commandsDir); + + System.out.println("Writing permissions wiki table..."); + writePermissionsWikiTable(commandClasses); + System.out.println("Writing Bukkit plugin.yml..."); + writeBukkitYAML(); + + System.out.println("Done!"); + } + + private static List> getCommandClasses(File dir) { + List> classes = new ArrayList>(); + + classes.add(BiomeCommands.class); + classes.add(ChunkCommands.class); + classes.add(ClipboardCommands.class); + classes.add(GeneralCommands.class); + classes.add(GenerationCommands.class); + classes.add(HistoryCommands.class); + classes.add(NavigationCommands.class); + classes.add(RegionCommands.class); + classes.add(ScriptingCommands.class); + classes.add(SelectionCommands.class); + classes.add(SnapshotUtilCommands.class); + classes.add(ToolUtilCommands.class); + classes.add(ToolCommands.class); + classes.add(UtilityCommands.class); + + /*for (File f : dir.listFiles()) { + if (!f.getName().matches("^.*\\.java$")) { + continue; + } + + String className = "com.sk89q.worldedit.commands." + + f.getName().substring(0, f.getName().lastIndexOf(".")); + + Class cls; + try { + cls = Class.forName(className, true, + Thread.currentThread().getContextClassLoader()); + } catch (ClassNotFoundException e) { + continue; + } + + classes.add(cls); + }*/ + + return classes; + } + + private static void writePermissionsWikiTable(List> commandClasses) + throws IOException { + FileOutputStream stream = null; + try { + stream = new FileOutputStream("wiki_permissions.txt"); + PrintStream print = new PrintStream(stream); + _writePermissionsWikiTable(print, commandClasses, "/"); + } finally { + if (stream != null) { + stream.close(); + } + } + } + + private static void _writePermissionsWikiTable(PrintStream stream, + List> commandClasses, String prefix) { + + for (Class cls : commandClasses) { + for (Method method : cls.getMethods()) { + if (!method.isAnnotationPresent(Command.class)) { + continue; + } + + Command cmd = method.getAnnotation(Command.class); + + stream.println("|-"); + stream.print("| " + prefix + cmd.aliases()[0]); + stream.print(" || "); + + if (method.isAnnotationPresent(CommandPermissions.class)) { + CommandPermissions perms = + method.getAnnotation(CommandPermissions.class); + + String[] permKeys = perms.value(); + for (int i = 0; i < permKeys.length; ++i) { + if (i > 0) { + stream.print(", "); + } + stream.print(permKeys[i]); + } + } + + stream.print(" || "); + + boolean firstAlias = true; + if (cmd.aliases().length != 0) { + for (String alias : cmd.aliases()) { + if (!firstAlias) stream.print("
"); + stream.print(prefix + alias); + firstAlias = false; + } + } + + stream.print(" || "); + + if (cmd.flags() != null && !cmd.flags().equals("")) { + stream.print(cmd.flags()); + } + + stream.print(" || "); + + if (cmd.desc() != null && !cmd.desc().equals("")) { + stream.print(cmd.desc()); + } + + stream.println(); + + if (method.isAnnotationPresent(NestedCommand.class)) { + NestedCommand nested = + method.getAnnotation(NestedCommand.class); + + Class[] nestedClasses = nested.value(); + _writePermissionsWikiTable(stream, + Arrays.asList(nestedClasses), + prefix + cmd.aliases()[0] + " "); + } + } + } + } + + private static void writeBukkitYAML() + throws IOException { + FileOutputStream stream = null; + try { + stream = new FileOutputStream("plugin.yml"); + PrintStream print = new PrintStream(stream); + _writeBukkitYAML(print); + } finally { + if (stream != null) { + stream.close(); + } + } + } + + private static void _writeBukkitYAML(PrintStream stream) { + + stream.println("name: WorldEdit"); + stream.println("main: com.sk89q.worldedit.bukkit.WorldEditPlugin"); + stream.println("version: ${project.version}"); + stream.println("softdepend: [Spout] #hack to fix trove errors"); + + stream.println(); + stream.println(); + stream.println("# Permissions aren't here. Read http://wiki.sk89q.com/wiki/WEPIF/DinnerPerms"); + stream.println("# for how WorldEdit permissions actually work."); + } +} diff --git a/src/main/java/com/sk89q/worldedit/filtering/GaussianKernel.java b/src/main/java/com/sk89q/worldedit/math/convolution/GaussianKernel.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/filtering/GaussianKernel.java rename to src/main/java/com/sk89q/worldedit/math/convolution/GaussianKernel.java index 2aa4ac957..44813a426 100644 --- a/src/main/java/com/sk89q/worldedit/filtering/GaussianKernel.java +++ b/src/main/java/com/sk89q/worldedit/math/convolution/GaussianKernel.java @@ -1,57 +1,57 @@ -// $Id$ -/* - * WorldEditLibrary - * Copyright (C) 2010 sk89q 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.filtering; - -import java.awt.image.Kernel; - -/** - * A Gaussian Kernel generator (2D bellcurve) - * - * @author Grum - */ - -public class GaussianKernel extends Kernel { - - /** - * Constructor of the kernel - * - * @param radius the resulting diameter will be radius * 2 + 1 - * @param sigma controls 'flatness' - */ - - public GaussianKernel(int radius, double sigma) { - super(radius * 2 + 1, radius * 2 + 1, createKernel(radius, sigma)); - } - - private static float[] createKernel(int radius, double sigma) { - int diameter = radius * 2 + 1; - float[] data = new float[diameter * diameter]; - - double sigma22 = 2 * sigma * sigma; - double constant = Math.PI * sigma22; - for (int y = -radius; y <= radius; ++y) { - for (int x = -radius; x <= radius; ++x) { - data[(y + radius) * diameter + x + radius] = (float) (Math.exp(-(x * x + y * y) / sigma22) / constant); - } - } - - return data; - } -} +// $Id$ +/* + * WorldEditLibrary + * Copyright (C) 2010 sk89q 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.math.convolution; + +import java.awt.image.Kernel; + +/** + * A Gaussian Kernel generator (2D bellcurve) + * + * @author Grum + */ + +public class GaussianKernel extends Kernel { + + /** + * Constructor of the kernel + * + * @param radius the resulting diameter will be radius * 2 + 1 + * @param sigma controls 'flatness' + */ + + public GaussianKernel(int radius, double sigma) { + super(radius * 2 + 1, radius * 2 + 1, createKernel(radius, sigma)); + } + + private static float[] createKernel(int radius, double sigma) { + int diameter = radius * 2 + 1; + float[] data = new float[diameter * diameter]; + + double sigma22 = 2 * sigma * sigma; + double constant = Math.PI * sigma22; + for (int y = -radius; y <= radius; ++y) { + for (int x = -radius; x <= radius; ++x) { + data[(y + radius) * diameter + x + radius] = (float) (Math.exp(-(x * x + y * y) / sigma22) / constant); + } + } + + return data; + } +} diff --git a/src/main/java/com/sk89q/worldedit/HeightMap.java b/src/main/java/com/sk89q/worldedit/math/convolution/HeightMap.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/HeightMap.java rename to src/main/java/com/sk89q/worldedit/math/convolution/HeightMap.java index d7f786599..e1ced85df 100644 --- a/src/main/java/com/sk89q/worldedit/HeightMap.java +++ b/src/main/java/com/sk89q/worldedit/math/convolution/HeightMap.java @@ -1,179 +1,181 @@ -// $Id$ -/* - * WorldEditLibrary - * Copyright (C) 2010 sk89q 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; - -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.blocks.BlockID; -import com.sk89q.worldedit.filtering.HeightMapFilter; -import com.sk89q.worldedit.regions.Region; - -/** - * Allows applications of Kernels onto the region's heightmap. - * Currently only used for smoothing (with a GaussianKernel). - * - * @author Grum - */ - -public class HeightMap { - private int[] data; - private int width; - private int height; - - private Region region; - private EditSession session; - - /** - * Constructs the HeightMap - * - * @param session - * @param region - */ - public HeightMap(EditSession session, Region region) { - this(session, region, false); - } - - /** - * Constructs the HeightMap - * - * @param session - * @param region - * @param naturalOnly ignore non-natural blocks - */ - public HeightMap(EditSession session, Region region, boolean naturalOnly) { - this.session = session; - this.region = region; - - this.width = region.getWidth(); - this.height = region.getLength(); - - int minX = region.getMinimumPoint().getBlockX(); - int minY = region.getMinimumPoint().getBlockY(); - int minZ = region.getMinimumPoint().getBlockZ(); - int maxY = region.getMaximumPoint().getBlockY(); - - // Store current heightmap data - data = new int[width * height]; - for (int z = 0; z < height; ++z) { - for (int x = 0; x < width; ++x) { - data[z * width + x] = session.getHighestTerrainBlock(x + minX, z + minZ, minY, maxY, naturalOnly); - } - } - } - - /** - * Apply the filter 'iterations' amount times. - * - * @param filter - * @param iterations - * @return number of blocks affected - * @throws MaxChangedBlocksException - */ - - public int applyFilter(HeightMapFilter filter, int iterations) throws MaxChangedBlocksException { - int[] newData = new int[data.length]; - System.arraycopy(data, 0, newData, 0, data.length); - - for (int i = 0; i < iterations; ++i) { - newData = filter.filter(newData, width, height); - } - - return apply(newData); - } - - /** - * Apply a raw heightmap to the region - * - * @param data - * @return number of blocks affected - * @throws MaxChangedBlocksException - */ - - public int apply(int[] data) throws MaxChangedBlocksException { - Vector minY = region.getMinimumPoint(); - int originX = minY.getBlockX(); - int originY = minY.getBlockY(); - int originZ = minY.getBlockZ(); - - int maxY = region.getMaximumPoint().getBlockY(); - BaseBlock fillerAir = new BaseBlock(BlockID.AIR); - - int blocksChanged = 0; - - // Apply heightmap - for (int z = 0; z < height; ++z) { - for (int x = 0; x < width; ++x) { - int index = z * width + x; - int curHeight = this.data[index]; - - // Clamp newHeight within the selection area - int newHeight = Math.min(maxY, data[index]); - - // Offset x,z to be 'real' coordinates - int X = x + originX; - int Z = z + originZ; - - // We are keeping the topmost blocks so take that in account for the scale - double scale = (double) (curHeight - originY) / (double) (newHeight - originY); - - // Depending on growing or shrinking we need to start at the bottom or top - if (newHeight > curHeight) { - // Set the top block of the column to be the same type (this might go wrong with rounding) - BaseBlock existing = session.getBlock(new Vector(X, curHeight, Z)); - - // Skip water/lava - if (existing.getType() != BlockID.WATER && existing.getType() != BlockID.STATIONARY_WATER - && existing.getType() != BlockID.LAVA && existing.getType() != BlockID.STATIONARY_LAVA) { - session.setBlock(new Vector(X, newHeight, Z), existing); - ++blocksChanged; - - // Grow -- start from 1 below top replacing airblocks - for (int y = newHeight - 1 - originY; y >= 0; --y) { - int copyFrom = (int) (y * scale); - session.setBlock(new Vector(X, originY + y, Z), session.getBlock(new Vector(X, originY + copyFrom, Z))); - ++blocksChanged; - } - } - } else if (curHeight > newHeight) { - // Shrink -- start from bottom - for (int y = 0; y < newHeight - originY; ++y) { - int copyFrom = (int) (y * scale); - session.setBlock(new Vector(X, originY + y, Z), session.getBlock(new Vector(X, originY + copyFrom, Z))); - ++blocksChanged; - } - - // Set the top block of the column to be the same type - // (this could otherwise go wrong with rounding) - session.setBlock(new Vector(X, newHeight, Z), session.getBlock(new Vector(X, curHeight, Z))); - ++blocksChanged; - - // Fill rest with air - for (int y = newHeight + 1; y <= curHeight; ++y) { - session.setBlock(new Vector(X, y, Z), fillerAir); - ++blocksChanged; - } - } - } - } - - // Drop trees to the floor -- TODO - - return blocksChanged; - } -} +// $Id$ +/* + * WorldEditLibrary + * Copyright (C) 2010 sk89q 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.math.convolution; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockID; +import com.sk89q.worldedit.regions.Region; + +/** + * Allows applications of Kernels onto the region's heightmap. + * Currently only used for smoothing (with a GaussianKernel). + * + * @author Grum + */ + +public class HeightMap { + private int[] data; + private int width; + private int height; + + private Region region; + private EditSession session; + + /** + * Constructs the HeightMap + * + * @param session + * @param region + */ + public HeightMap(EditSession session, Region region) { + this(session, region, false); + } + + /** + * Constructs the HeightMap + * + * @param session + * @param region + * @param naturalOnly ignore non-natural blocks + */ + public HeightMap(EditSession session, Region region, boolean naturalOnly) { + this.session = session; + this.region = region; + + this.width = region.getWidth(); + this.height = region.getLength(); + + int minX = region.getMinimumPoint().getBlockX(); + int minY = region.getMinimumPoint().getBlockY(); + int minZ = region.getMinimumPoint().getBlockZ(); + int maxY = region.getMaximumPoint().getBlockY(); + + // Store current heightmap data + data = new int[width * height]; + for (int z = 0; z < height; ++z) { + for (int x = 0; x < width; ++x) { + data[z * width + x] = session.getHighestTerrainBlock(x + minX, z + minZ, minY, maxY, naturalOnly); + } + } + } + + /** + * Apply the filter 'iterations' amount times. + * + * @param filter + * @param iterations + * @return number of blocks affected + * @throws MaxChangedBlocksException + */ + + public int applyFilter(HeightMapFilter filter, int iterations) throws MaxChangedBlocksException { + int[] newData = new int[data.length]; + System.arraycopy(data, 0, newData, 0, data.length); + + for (int i = 0; i < iterations; ++i) { + newData = filter.filter(newData, width, height); + } + + return apply(newData); + } + + /** + * Apply a raw heightmap to the region + * + * @param data + * @return number of blocks affected + * @throws MaxChangedBlocksException + */ + + public int apply(int[] data) throws MaxChangedBlocksException { + Vector minY = region.getMinimumPoint(); + int originX = minY.getBlockX(); + int originY = minY.getBlockY(); + int originZ = minY.getBlockZ(); + + int maxY = region.getMaximumPoint().getBlockY(); + BaseBlock fillerAir = new BaseBlock(BlockID.AIR); + + int blocksChanged = 0; + + // Apply heightmap + for (int z = 0; z < height; ++z) { + for (int x = 0; x < width; ++x) { + int index = z * width + x; + int curHeight = this.data[index]; + + // Clamp newHeight within the selection area + int newHeight = Math.min(maxY, data[index]); + + // Offset x,z to be 'real' coordinates + int X = x + originX; + int Z = z + originZ; + + // We are keeping the topmost blocks so take that in account for the scale + double scale = (double) (curHeight - originY) / (double) (newHeight - originY); + + // Depending on growing or shrinking we need to start at the bottom or top + if (newHeight > curHeight) { + // Set the top block of the column to be the same type (this might go wrong with rounding) + BaseBlock existing = session.getBlock(new Vector(X, curHeight, Z)); + + // Skip water/lava + if (existing.getType() != BlockID.WATER && existing.getType() != BlockID.STATIONARY_WATER + && existing.getType() != BlockID.LAVA && existing.getType() != BlockID.STATIONARY_LAVA) { + session.setBlock(new Vector(X, newHeight, Z), existing); + ++blocksChanged; + + // Grow -- start from 1 below top replacing airblocks + for (int y = newHeight - 1 - originY; y >= 0; --y) { + int copyFrom = (int) (y * scale); + session.setBlock(new Vector(X, originY + y, Z), session.getBlock(new Vector(X, originY + copyFrom, Z))); + ++blocksChanged; + } + } + } else if (curHeight > newHeight) { + // Shrink -- start from bottom + for (int y = 0; y < newHeight - originY; ++y) { + int copyFrom = (int) (y * scale); + session.setBlock(new Vector(X, originY + y, Z), session.getBlock(new Vector(X, originY + copyFrom, Z))); + ++blocksChanged; + } + + // Set the top block of the column to be the same type + // (this could otherwise go wrong with rounding) + session.setBlock(new Vector(X, newHeight, Z), session.getBlock(new Vector(X, curHeight, Z))); + ++blocksChanged; + + // Fill rest with air + for (int y = newHeight + 1; y <= curHeight; ++y) { + session.setBlock(new Vector(X, y, Z), fillerAir); + ++blocksChanged; + } + } + } + } + + // Drop trees to the floor -- TODO + + return blocksChanged; + } +} diff --git a/src/main/java/com/sk89q/worldedit/filtering/HeightMapFilter.java b/src/main/java/com/sk89q/worldedit/math/convolution/HeightMapFilter.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/filtering/HeightMapFilter.java rename to src/main/java/com/sk89q/worldedit/math/convolution/HeightMapFilter.java index 8078f5f7f..3f802f295 100644 --- a/src/main/java/com/sk89q/worldedit/filtering/HeightMapFilter.java +++ b/src/main/java/com/sk89q/worldedit/math/convolution/HeightMapFilter.java @@ -1,120 +1,120 @@ -// $Id$ -/* - * WorldEditLibrary - * Copyright (C) 2010 sk89q 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.filtering; - -import java.awt.image.Kernel; - -/** - * Allows applications of Kernels onto the region's heightmap. - * Only used for smoothing (with a GaussianKernel). - * - * @author Grum - */ - -public class HeightMapFilter { - private Kernel kernel; - - /** - * Construct the HeightMapFilter object. - * - * @param kernel - */ - public HeightMapFilter(Kernel kernel) { - this.kernel = kernel; - } - - /** - * Construct the HeightMapFilter object. - * - * @param kernelWidth - * @param kernelHeight - * @param kernelData - */ - public HeightMapFilter(int kernelWidth, int kernelHeight, float[] kernelData) { - this.kernel = new Kernel(kernelWidth, kernelHeight, kernelData); - } - - /** - * @return the kernel - */ - public Kernel getKernel() { - return kernel; - } - - /** - * Set Kernel - * - * @param kernel - */ - public void setKernel(Kernel kernel) { - this.kernel = kernel; - } - - /** - * Filter with a 2D kernel - * - * @param inData - * @param width - * @param height - * @return the modified heightmap - */ - public int[] filter(int[] inData, int width, int height) { - int index = 0; - float[] matrix = kernel.getKernelData(null); - int[] outData = new int[inData.length]; - - int kh = kernel.getHeight(); - int kw = kernel.getWidth(); - int kox = kernel.getXOrigin(); - int koy = kernel.getYOrigin(); - - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { - float z = 0; - - for (int ky = 0; ky < kh; ++ky) { - int offsetY = y + ky - koy; - // Clamp coordinates inside data - if (offsetY < 0 || offsetY >= height) { - offsetY = y; - } - - offsetY *= width; - - int matrixOffset = ky * kw; - for (int kx = 0; kx < kw; ++kx) { - float f = matrix[matrixOffset + kx]; - if (f == 0) continue; - - int offsetX = x + kx - kox; - // Clamp coordinates inside data - if (offsetX < 0 || offsetX >= width) { - offsetX = x; - } - - z += f * inData[offsetY + offsetX]; - } - } - outData[index++] = (int) (z + 0.5); - } - } - return outData; - } -} +// $Id$ +/* + * WorldEditLibrary + * Copyright (C) 2010 sk89q 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.math.convolution; + +import java.awt.image.Kernel; + +/** + * Allows applications of Kernels onto the region's heightmap. + * Only used for smoothing (with a GaussianKernel). + * + * @author Grum + */ + +public class HeightMapFilter { + private Kernel kernel; + + /** + * Construct the HeightMapFilter object. + * + * @param kernel + */ + public HeightMapFilter(Kernel kernel) { + this.kernel = kernel; + } + + /** + * Construct the HeightMapFilter object. + * + * @param kernelWidth + * @param kernelHeight + * @param kernelData + */ + public HeightMapFilter(int kernelWidth, int kernelHeight, float[] kernelData) { + this.kernel = new Kernel(kernelWidth, kernelHeight, kernelData); + } + + /** + * @return the kernel + */ + public Kernel getKernel() { + return kernel; + } + + /** + * Set Kernel + * + * @param kernel + */ + public void setKernel(Kernel kernel) { + this.kernel = kernel; + } + + /** + * Filter with a 2D kernel + * + * @param inData + * @param width + * @param height + * @return the modified heightmap + */ + public int[] filter(int[] inData, int width, int height) { + int index = 0; + float[] matrix = kernel.getKernelData(null); + int[] outData = new int[inData.length]; + + int kh = kernel.getHeight(); + int kw = kernel.getWidth(); + int kox = kernel.getXOrigin(); + int koy = kernel.getYOrigin(); + + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + float z = 0; + + for (int ky = 0; ky < kh; ++ky) { + int offsetY = y + ky - koy; + // Clamp coordinates inside data + if (offsetY < 0 || offsetY >= height) { + offsetY = y; + } + + offsetY *= width; + + int matrixOffset = ky * kw; + for (int kx = 0; kx < kw; ++kx) { + float f = matrix[matrixOffset + kx]; + if (f == 0) continue; + + int offsetX = x + kx - kox; + // Clamp coordinates inside data + if (offsetX < 0 || offsetX >= width) { + offsetX = x; + } + + z += f * inData[offsetY + offsetX]; + } + } + outData[index++] = (int) (z + 0.5); + } + } + return outData; + } +} diff --git a/src/main/java/com/sk89q/worldedit/filtering/LinearKernel.java b/src/main/java/com/sk89q/worldedit/math/convolution/LinearKernel.java similarity index 93% rename from src/main/java/com/sk89q/worldedit/filtering/LinearKernel.java rename to src/main/java/com/sk89q/worldedit/math/convolution/LinearKernel.java index ea8aa98ab..1f52474ee 100644 --- a/src/main/java/com/sk89q/worldedit/filtering/LinearKernel.java +++ b/src/main/java/com/sk89q/worldedit/math/convolution/LinearKernel.java @@ -1,44 +1,44 @@ -// $Id$ -/* - * WorldEditLibrary - * Copyright (C) 2010 sk89q 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.filtering; - -import java.awt.image.Kernel; - -/** - * A linear Kernel generator (all cells weight the same) - * - * @author Grum - */ - -public class LinearKernel extends Kernel { - - public LinearKernel(int radius) { - super(radius * 2 + 1, radius * 2 + 1, createKernel(radius)); - } - - private static float[] createKernel(int radius) { - int diameter = radius * 2 + 1; - float[] data = new float[diameter * diameter]; - - for (int i = 0; i < data.length; data[i++] = 1.0f / data.length) ; - - return data; - } -} +// $Id$ +/* + * WorldEditLibrary + * Copyright (C) 2010 sk89q 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.math.convolution; + +import java.awt.image.Kernel; + +/** + * A linear Kernel generator (all cells weight the same) + * + * @author Grum + */ + +public class LinearKernel extends Kernel { + + public LinearKernel(int radius) { + super(radius * 2 + 1, radius * 2 + 1, createKernel(radius)); + } + + private static float[] createKernel(int radius) { + int diameter = radius * 2 + 1; + float[] data = new float[diameter * diameter]; + + for (int i = 0; i < data.length; data[i++] = 1.0f / data.length) ; + + return data; + } +} diff --git a/src/main/java/com/sk89q/worldedit/interpolation/Interpolation.java b/src/main/java/com/sk89q/worldedit/math/interpolation/Interpolation.java similarity index 97% rename from src/main/java/com/sk89q/worldedit/interpolation/Interpolation.java rename to src/main/java/com/sk89q/worldedit/math/interpolation/Interpolation.java index 62d1412e2..c07d72860 100644 --- a/src/main/java/com/sk89q/worldedit/interpolation/Interpolation.java +++ b/src/main/java/com/sk89q/worldedit/math/interpolation/Interpolation.java @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package com.sk89q.worldedit.interpolation; +package com.sk89q.worldedit.math.interpolation; import java.util.List; diff --git a/src/main/java/com/sk89q/worldedit/interpolation/KochanekBartelsInterpolation.java b/src/main/java/com/sk89q/worldedit/math/interpolation/KochanekBartelsInterpolation.java similarity index 99% rename from src/main/java/com/sk89q/worldedit/interpolation/KochanekBartelsInterpolation.java rename to src/main/java/com/sk89q/worldedit/math/interpolation/KochanekBartelsInterpolation.java index 72dd305d3..81a338011 100644 --- a/src/main/java/com/sk89q/worldedit/interpolation/KochanekBartelsInterpolation.java +++ b/src/main/java/com/sk89q/worldedit/math/interpolation/KochanekBartelsInterpolation.java @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package com.sk89q.worldedit.interpolation; +package com.sk89q.worldedit.math.interpolation; import java.util.Collections; import java.util.List; diff --git a/src/main/java/com/sk89q/worldedit/interpolation/LinearInterpolation.java b/src/main/java/com/sk89q/worldedit/math/interpolation/LinearInterpolation.java similarity index 98% rename from src/main/java/com/sk89q/worldedit/interpolation/LinearInterpolation.java rename to src/main/java/com/sk89q/worldedit/math/interpolation/LinearInterpolation.java index 68fb2aaad..0da212a8d 100644 --- a/src/main/java/com/sk89q/worldedit/interpolation/LinearInterpolation.java +++ b/src/main/java/com/sk89q/worldedit/math/interpolation/LinearInterpolation.java @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package com.sk89q.worldedit.interpolation; +package com.sk89q.worldedit.math.interpolation; import java.util.List; diff --git a/src/main/java/com/sk89q/worldedit/interpolation/Node.java b/src/main/java/com/sk89q/worldedit/math/interpolation/Node.java similarity index 97% rename from src/main/java/com/sk89q/worldedit/interpolation/Node.java rename to src/main/java/com/sk89q/worldedit/math/interpolation/Node.java index 6e1a53e18..d4ccbf5a6 100644 --- a/src/main/java/com/sk89q/worldedit/interpolation/Node.java +++ b/src/main/java/com/sk89q/worldedit/math/interpolation/Node.java @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package com.sk89q.worldedit.interpolation; +package com.sk89q.worldedit.math.interpolation; import com.sk89q.worldedit.Vector; diff --git a/src/main/java/com/sk89q/worldedit/interpolation/ReparametrisingInterpolation.java b/src/main/java/com/sk89q/worldedit/math/interpolation/ReparametrisingInterpolation.java similarity index 98% rename from src/main/java/com/sk89q/worldedit/interpolation/ReparametrisingInterpolation.java rename to src/main/java/com/sk89q/worldedit/math/interpolation/ReparametrisingInterpolation.java index 047a38df1..6fe515762 100644 --- a/src/main/java/com/sk89q/worldedit/interpolation/ReparametrisingInterpolation.java +++ b/src/main/java/com/sk89q/worldedit/math/interpolation/ReparametrisingInterpolation.java @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package com.sk89q.worldedit.interpolation; +package com.sk89q.worldedit.math.interpolation; import java.util.List; import java.util.Map.Entry; diff --git a/src/main/java/com/sk89q/worldedit/noise/NoiseGenerator.java b/src/main/java/com/sk89q/worldedit/math/noise/NoiseGenerator.java similarity index 81% rename from src/main/java/com/sk89q/worldedit/noise/NoiseGenerator.java rename to src/main/java/com/sk89q/worldedit/math/noise/NoiseGenerator.java index 7e95f5f4a..fde26b6b3 100644 --- a/src/main/java/com/sk89q/worldedit/noise/NoiseGenerator.java +++ b/src/main/java/com/sk89q/worldedit/math/noise/NoiseGenerator.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.noise; +package com.sk89q.worldedit.math.noise; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector2D; @@ -28,7 +28,8 @@ import com.sk89q.worldedit.Vector2D; public interface NoiseGenerator { /** - * Get the noise for the given position. + * Get the noise value for the given position. The returned value may + * change on every future call for the same position. * * @param position the position * @return a noise value between 0 (inclusive) and 1 (inclusive) @@ -36,7 +37,8 @@ public interface NoiseGenerator { float noise(Vector2D position); /** - * Get the noise for the given position. + * Get the noise value for the given position. The returned value may + * change on every future call for the same position. * * @param position the position * @return a noise value between 0 (inclusive) and 1 (inclusive) diff --git a/src/main/java/com/sk89q/worldedit/noise/RandomNoise.java b/src/main/java/com/sk89q/worldedit/math/noise/RandomNoise.java similarity index 90% rename from src/main/java/com/sk89q/worldedit/noise/RandomNoise.java rename to src/main/java/com/sk89q/worldedit/math/noise/RandomNoise.java index f60480e15..ff9ad9f68 100644 --- a/src/main/java/com/sk89q/worldedit/noise/RandomNoise.java +++ b/src/main/java/com/sk89q/worldedit/math/noise/RandomNoise.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.noise; +package com.sk89q.worldedit.math.noise; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector2D; @@ -25,7 +25,8 @@ import com.sk89q.worldedit.Vector2D; import java.util.Random; /** - * Generates noise non-deterministically using {@link java.util.Random}. + * Generates noise using {@link java.util.Random}. Every time a noise + * generating function is called, a new value will be returned. */ public class RandomNoise implements NoiseGenerator { diff --git a/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java b/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java new file mode 100644 index 000000000..475751f8b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java @@ -0,0 +1,299 @@ +/* + * 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.math.transform; + +import com.sk89q.worldedit.Vector; + +/** + * An affine transform. + *

+ * This class is from the + * that, then this affine transform. + * + * @param that the transform to apply first + * @return the composition this * that + */ + public AffineTransform concatenate(AffineTransform that) { + double n00 = m00 * that.m00 + m01 * that.m10 + m02 * that.m20; + double n01 = m00 * that.m01 + m01 * that.m11 + m02 * that.m21; + double n02 = m00 * that.m02 + m01 * that.m12 + m02 * that.m22; + double n03 = m00 * that.m03 + m01 * that.m13 + m02 * that.m23 + m03; + double n10 = m10 * that.m00 + m11 * that.m10 + m12 * that.m20; + double n11 = m10 * that.m01 + m11 * that.m11 + m12 * that.m21; + double n12 = m10 * that.m02 + m11 * that.m12 + m12 * that.m22; + double n13 = m10 * that.m03 + m11 * that.m13 + m12 * that.m23 + m13; + double n20 = m20 * that.m00 + m21 * that.m10 + m22 * that.m20; + double n21 = m20 * that.m01 + m21 * that.m11 + m22 * that.m21; + double n22 = m20 * that.m02 + m21 * that.m12 + m22 * that.m22; + double n23 = m20 * that.m03 + m21 * that.m13 + m22 * that.m23 + m23; + return new AffineTransform( + n00, n01, n02, n03, + n10, n11, n12, n13, + n20, n21, n22, n23); + } + + /** + * Return the affine transform created by applying first this affine + * transform, then the affine transform given by that. + * + * @param that the transform to apply in a second step + * @return the composition that * this + */ + public AffineTransform preConcatenate(AffineTransform that) { + double n00 = that.m00 * m00 + that.m01 * m10 + that.m02 * m20; + double n01 = that.m00 * m01 + that.m01 * m11 + that.m02 * m21; + double n02 = that.m00 * m02 + that.m01 * m12 + that.m02 * m22; + double n03 = that.m00 * m03 + that.m01 * m13 + that.m02 * m23 + that.m03; + double n10 = that.m10 * m00 + that.m11 * m10 + that.m12 * m20; + double n11 = that.m10 * m01 + that.m11 * m11 + that.m12 * m21; + double n12 = that.m10 * m02 + that.m11 * m12 + that.m12 * m22; + double n13 = that.m10 * m03 + that.m11 * m13 + that.m12 * m23 + that.m13; + double n20 = that.m20 * m00 + that.m21 * m10 + that.m22 * m20; + double n21 = that.m20 * m01 + that.m21 * m11 + that.m22 * m21; + double n22 = that.m20 * m02 + that.m21 * m12 + that.m22 * m22; + double n23 = that.m20 * m03 + that.m21 * m13 + that.m22 * m23 + that.m23; + return new AffineTransform( + n00, n01, n02, n03, + n10, n11, n12, n13, + n20, n21, n22, n23); + } + + public AffineTransform translate(Vector vec) { + return translate(vec.getX(), vec.getY(), vec.getZ()); + } + + public AffineTransform translate(double x, double y, double z) { + return concatenate(new AffineTransform(1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z)); + } + + public AffineTransform rotateX(double theta) { + double cot = Math.cos(theta); + double sit = Math.sin(theta); + return concatenate( + new AffineTransform( + 1, 0, 0, 0, + 0, cot, -sit, 0, + 0, sit, cot, 0)); + } + + public AffineTransform rotateY(double theta) { + double cot = Math.cos(theta); + double sit = Math.sin(theta); + return concatenate( + new AffineTransform( + cot, 0, sit, 0, + 0, 1, 0, 0, + -sit, 0, cot, 0)); + } + + public AffineTransform rotateZ(double theta) { + double cot = Math.cos(theta); + double sit = Math.sin(theta); + return concatenate( + new AffineTransform( + cot, -sit, 0, 0, + sit, cot, 0, 0, + 0, 0, 1, 0)); + } + + public AffineTransform scale(double s) { + return scale(s, s, s); + } + + public AffineTransform scale(double sx, double sy, double sz) { + return concatenate(new AffineTransform(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0)); + } + + @Override + public Vector apply(Vector vector) { + return new Vector( + vector.getX() * m00 + vector.getY() * m01 + vector.getZ() * m02 + m03, + vector.getX() * m10 + vector.getY() * m11 + vector.getZ() * m12 + m13, + vector.getX() * m20 + vector.getY() * m21 + vector.getZ() * m22 + m23); + } + + @Override + public Transform combine(Transform other) { + if (other instanceof AffineTransform) { + return concatenate((AffineTransform) other); + } else { + return new CombinedTransform(this, other); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/sk89q/worldedit/math/transform/CombinedTransform.java b/src/main/java/com/sk89q/worldedit/math/transform/CombinedTransform.java new file mode 100644 index 000000000..893e3c384 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/transform/CombinedTransform.java @@ -0,0 +1,77 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.math.transform; + +import com.sk89q.worldedit.Vector; + +import java.util.Arrays; +import java.util.Collection; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Combines several transforms in order. + */ +public class CombinedTransform implements Transform { + + private final Transform[] transforms; + + /** + * Create a new combined transformation. + * + * @param transforms a list of transformations + */ + public CombinedTransform(Transform... transforms) { + checkNotNull(transforms); + this.transforms = Arrays.copyOf(transforms, transforms.length); + } + + /** + * Create a new combined transformation. + * + * @param transforms a list of transformations + */ + public CombinedTransform(Collection transforms) { + this(transforms.toArray(new Transform[checkNotNull(transforms).size()])); + } + + @Override + public Vector apply(Vector vector) { + for (Transform transform : transforms) { + vector = transform.apply(vector); + } + return vector; + } + + @Override + public Transform combine(Transform other) { + checkNotNull(other); + if (other instanceof CombinedTransform) { + CombinedTransform combinedOther = (CombinedTransform) other; + Transform[] newTransforms = new Transform[transforms.length + combinedOther.transforms.length]; + System.arraycopy(transforms, 0, newTransforms, 0, transforms.length); + System.arraycopy(combinedOther.transforms, 0, newTransforms, transforms.length, combinedOther.transforms.length); + return new CombinedTransform(newTransforms); + } else { + return new CombinedTransform(this, other); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/math/transform/Identity.java b/src/main/java/com/sk89q/worldedit/math/transform/Identity.java new file mode 100644 index 000000000..e13547de1 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/transform/Identity.java @@ -0,0 +1,42 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.math.transform; + +import com.sk89q.worldedit.Vector; + +/** + * Makes no transformation to given vectors. + */ +public class Identity implements Transform { + + @Override + public Vector apply(Vector vector) { + return vector; + } + + @Override + public Transform combine(Transform other) { + if (other instanceof Identity) { + return this; + } else { + return new CombinedTransform(this, other); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/math/transform/Transform.java b/src/main/java/com/sk89q/worldedit/math/transform/Transform.java new file mode 100644 index 000000000..38aba52e9 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/math/transform/Transform.java @@ -0,0 +1,38 @@ +/* + * 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.math.transform; + +import com.google.common.base.Function; +import com.sk89q.worldedit.Vector; + +/** + * Makes a transformation of {@link Vector}s. + */ +public interface Transform extends Function { + + /** + * Create a new {@link Transform} that combines this transform with another. + * + * @param other the other transform to occur second + * @return a new transform + */ + Transform combine(Transform other); + +} diff --git a/src/main/java/com/sk89q/worldedit/operation/GroundFindingFunction.java b/src/main/java/com/sk89q/worldedit/operation/GroundFindingFunction.java deleted file mode 100644 index 63f0f7715..000000000 --- a/src/main/java/com/sk89q/worldedit/operation/GroundFindingFunction.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU 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.operation; - -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.Vector2D; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.blocks.BlockID; -import com.sk89q.worldedit.regions.Region; - -/** - * An abstract implementation of {@link com.sk89q.worldedit.operation.FlatRegionFunction} - * that searches for the first "ground" block." A ground block is found when the - * method {@link #shouldPassThrough(Vector, BaseBlock)} returns false, which, by default, - * does so for all non-air blocks. - *

- * This function starts from the provided upperY in each block column and traverses - * down the column until it finds the first ground block, at which point - * {@link #apply(Vector, BaseBlock)} is called with the position and the - * {@link BaseBlock} for the found ground block. Implementations that want - * to skip certain columns (and avoid the ground search) can override - * {@link #shouldContinue(com.sk89q.worldedit.Vector2D)} and return true as necessary. - */ -public abstract class GroundFindingFunction implements FlatRegionFunction { - - private final EditSession editSession; - private int lowerY; - private int upperY; - - /** - * Create a new instance. - * - * @param editSession the edit session - */ - protected GroundFindingFunction(EditSession editSession) { - this.editSession = editSession; - checkYBounds(); - } - - /** - * Check whether upperY is >= lowerY. - */ - private void checkYBounds() { - if (upperY < lowerY) { - throw new IllegalArgumentException("upperY must be greater than or equal to lowerY"); - } - } - - /** - * Get the upper Y coordinate to start the ground search from. - * - * @return the upper Y coordinate - */ - public int getUpperY() { - return upperY; - } - - /** - * Get the lower Y coordinate to end the ground search at. - * - * @return lowerY the lower Y coordinate - */ - public int getLowerY() { - return lowerY; - } - - /** - * Set the range of Y coordinates to perform a search for ground within. - * - * @param lowerY the lower Y coordinate - * @param upperY the upper Y coordinate (upperY >= lowerY) - */ - public void setRange(int lowerY, int upperY) { - this.lowerY = lowerY; - this.upperY = upperY; - checkYBounds(); - } - - /** - * Set the range of Y coordinates to perform a search for ground within from - * the minimum and maximum Y of the given region. - * - * @param region the region - */ - public void setRange(Region region) { - setRange(region.getMinimumPoint().getBlockY(), region.getMaximumPoint().getBlockY()); - } - - /** - * Increase the upper Y by the given amount. - * - * @param y the amount to increase the upper Y by - */ - public void raiseCeiling(int y) { - if (y <= 0) { - throw new IllegalArgumentException("Can't raise by a negative"); - } - upperY += y; - } - - @Override - public final boolean apply(Vector2D pt) throws WorldEditException { - // Don't want to be in the ground - if (!editSession.getBlock(pt.toVector(upperY + 1)).isAir()) { - return false; - } - - if (!shouldContinue(pt)) { - return false; - } - - for (int y = upperY + 1; y >= lowerY; --y) { - Vector testPt = pt.toVector(y); - BaseBlock block = editSession.getBlock(testPt); - - if (!shouldPassThrough(testPt, block)) { - return apply(testPt, block); - } - } - - return false; - } - - /** - * Returns whether a search for the ground should be performed for the given - * column. Return false if the column is to be skipped. - * - * @param pt the point - * @return true if the search should begin - */ - protected boolean shouldContinue(Vector2D pt) { - return true; - } - - /** - * Returns whether the given block should be "passed through" when - * conducting the ground search. - *

- * Examples of blocks where this method could return true include snow, tall - * grass, shrubs, and flowers. Note that this method will also receive - * calls on each air block so that condition must be handled. Be aware - * that blocks passed through are not automatically removed - * from the world, so implementations may need to remove the block - * immediately above the ground. - *

- * The default implementation only returns true for air blocks. - * - * @param position the position - * @param block the block - * @return true if the block should be passed through during the ground search - */ - protected boolean shouldPassThrough(Vector position, BaseBlock block) { - return block.getType() == BlockID.AIR; - } - - /** - * Apply the function to the given ground block. - *

- * Naive implementations may provide flowers, tall grass, and other - * blocks not often considered to be the ground as the ground block. - * - * @param position the position - * @param block the block - * @return true if something was changed - * @throws WorldEditException thrown on an error - */ - protected abstract boolean apply(Vector position, BaseBlock block) throws WorldEditException; - -} diff --git a/src/main/java/com/sk89q/worldedit/operation/GroundScatterFunction.java b/src/main/java/com/sk89q/worldedit/operation/GroundScatterFunction.java deleted file mode 100644 index 474d70214..000000000 --- a/src/main/java/com/sk89q/worldedit/operation/GroundScatterFunction.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU 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.operation; - -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.Vector2D; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.noise.NoiseGenerator; -import com.sk89q.worldedit.noise.RandomNoise; - -/** - * Randomly applies the given {@link RegionFunction} onto random ground blocks. - *

- * This class can be used to generate a structure randomly over an area. - */ -public class GroundScatterFunction extends GroundFindingFunction { - - private NoiseGenerator noiseGenerator; - private RegionFunction function; - private double density; - - /** - * Create a new instance using a {@link RandomNoise} as the noise generator. - * - * @param editSession the edit session - * @param function the function - */ - public GroundScatterFunction(EditSession editSession, RegionFunction function) { - this(editSession, function, new RandomNoise()); - } - - /** - * Create a new instance. - * - * @param editSession the edit session - * @param function the function - */ - public GroundScatterFunction(EditSession editSession, RegionFunction function, NoiseGenerator noiseGenerator) { - super(editSession); - this.function = function; - this.noiseGenerator = noiseGenerator; - } - - /** - * Get the density (0 <= density <= 1) which indicates the threshold that - * must be met for the function to be applied to a column. - * - * @return the density - */ - public double getDensity() { - return density; - } - - /** - * Set the density (0 <= density <= 1) which indicates the threshold that - * must be met for the function to be applied to a column. - * - * @param density the density - */ - public void setDensity(double density) { - this.density = density; - } - - /** - * Get the noise generator. - * - * @return the noise generator - */ - public NoiseGenerator getNoiseGenerator() { - return noiseGenerator; - } - - /** - * Set the noise generator. - * - * @param noiseGenerator the noise generator - */ - public void setNoiseGenerator(NoiseGenerator noiseGenerator) { - this.noiseGenerator = noiseGenerator; - } - - /** - * Get the function to apply. - * - * @return the region function - */ - public RegionFunction getFunction() { - return function; - } - - /** - * Set the function to apply. - * - * @param function the region function - */ - public void setFunction(RegionFunction function) { - this.function = function; - } - - @Override - protected boolean shouldContinue(Vector2D pt) { - return noiseGenerator.noise(pt) <= density; - } - - @Override - protected boolean apply(Vector position, BaseBlock block) throws WorldEditException { - return function.apply(position); - } -} diff --git a/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java b/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java index 90a4e7e59..b0276f636 100644 --- a/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java +++ b/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java @@ -19,18 +19,12 @@ package com.sk89q.worldedit.regions; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -import com.sk89q.worldedit.BlockVector; -import com.sk89q.worldedit.BlockVector2D; -import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.*; import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.Vector2D; -import com.sk89q.worldedit.data.ChunkStore; +import com.sk89q.worldedit.regions.iterator.RegionIterator; +import com.sk89q.worldedit.world.storage.ChunkStore; + +import java.util.*; public abstract class AbstractRegion implements Region { /** diff --git a/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java b/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java index 99d3f8925..71958c2b8 100644 --- a/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java +++ b/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java @@ -19,89 +19,165 @@ package com.sk89q.worldedit.regions; -import com.sk89q.worldedit.BlockVector; -import com.sk89q.worldedit.BlockVector2D; -import com.sk89q.worldedit.LocalWorld; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.Vector2D; -import com.sk89q.worldedit.data.ChunkStore; +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.world.storage.ChunkStore; + +import java.util.HashSet; import java.util.Iterator; import java.util.Set; -import java.util.HashSet; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; /** - * - * @author sk89q + * An axis-aligned cuboid. It can be defined using two corners of the cuboid. */ public class CuboidRegion extends AbstractRegion implements FlatRegion { - /** - * Store the first point. - */ + private Vector pos1; - /** - * Store the second point. - */ private Vector pos2; /** - * Construct a new instance of this cuboid region. + * Construct a new instance of this cuboid using two corners of the cuboid. * - * @param pos1 - * @param pos2 + * @param pos1 the first position + * @param pos2 the second position */ public CuboidRegion(Vector pos1, Vector pos2) { this(null, pos1, pos2); } /** - * Construct a new instance of this cuboid region. + * Construct a new instance of this cuboid using two corners of the cuboid. * - * @param world - * @param pos1 - * @param pos2 + * @param world the world + * @param pos1 the first position + * @param pos2 the second position */ public CuboidRegion(LocalWorld world, Vector pos1, Vector pos2) { super(world); + checkNotNull(pos1); + checkNotNull(pos2); this.pos1 = pos1; this.pos2 = pos2; + recalculate(); + } + + /** + * Get the first cuboid-defining corner. + * + * @return a position + */ + public Vector getPos1() { + return pos1; + } + + /** + * Set the first cuboid-defining corner. + * + * @param pos1 a position + */ + public void setPos1(Vector pos1) { + this.pos1 = pos1; + } + + /** + * Get the second cuboid-defining corner. + * + * @return a position + */ + public Vector getPos2() { + return pos2; + } + + /** + * Set the second cuboid-defining corner. + * + * @param pos2 a position + */ + public void setPos2(Vector pos2) { + this.pos2 = pos2; } /** - * Get the lower point of the cuboid. - * - * @return min point + * Clamps the cuboid according to boundaries of the world. */ - public Vector getMinimumPoint() { - return new Vector(Math.min(pos1.getX(), pos2.getX()), - Math.min(pos1.getY(), pos2.getY()), - Math.min(pos1.getZ(), pos2.getZ())); + private void recalculate() { + pos1 = pos1.clampY(0, world == null ? 255 : world.getMaxY()); + pos2 = pos2.clampY(0, world == null ? 255 : world.getMaxY()); } /** - * Get the upper point of the cuboid. + * Get a region that contains the faces of this cuboid. * - * @return max point + * @return a new complex region */ - public Vector getMaximumPoint() { - return new Vector(Math.max(pos1.getX(), pos2.getX()), - Math.max(pos1.getY(), pos2.getY()), - Math.max(pos1.getZ(), pos2.getZ())); + public Region getFaces() { + Vector min = getMinimumPoint(); + Vector max = getMaximumPoint(); + + return new RegionIntersection( + // Project to Z-Y plane + new CuboidRegion(pos1.setX(min.getX()), pos2.setX(min.getX())), + new CuboidRegion(pos1.setX(max.getX()), pos2.setX(max.getX())), + + // Project to X-Y plane + new CuboidRegion(pos1.setZ(min.getZ()), pos2.setZ(min.getZ())), + new CuboidRegion(pos1.setZ(max.getZ()), pos2.setZ(max.getZ())), + + // Project to the X-Z plane + new CuboidRegion(pos1.setY(min.getY()), pos2.setY(min.getY())), + new CuboidRegion(pos1.setY(max.getY()), pos2.setY(max.getY()))); } + /** + * Get a region that contains the walls (all faces but the ones parallel to + * the X-Z plane) of this cuboid. + * + * @return a new complex region + */ + public Region getWalls() { + Vector min = getMinimumPoint(); + Vector max = getMaximumPoint(); + + return new RegionIntersection( + // Project to Z-Y plane + new CuboidRegion(pos1.setX(min.getX()), pos2.setX(min.getX())), + new CuboidRegion(pos1.setX(max.getX()), pos2.setX(max.getX())), + + // Project to X-Y plane + new CuboidRegion(pos1.setZ(min.getZ()), pos2.setZ(min.getZ())), + new CuboidRegion(pos1.setZ(max.getZ()), pos2.setZ(max.getZ()))); + } + + @Override + public Vector getMinimumPoint() { + return new Vector(Math.min(pos1.getX(), pos2.getX()), + Math.min(pos1.getY(), pos2.getY()), + Math.min(pos1.getZ(), pos2.getZ())); + } + + @Override + public Vector getMaximumPoint() { + return new Vector(Math.max(pos1.getX(), pos2.getX()), + Math.max(pos1.getY(), pos2.getY()), + Math.max(pos1.getZ(), pos2.getZ())); + } + + @Override public int getMinimumY() { return Math.min(pos1.getBlockY(), pos2.getBlockY()); } + @Override public int getMaximumY() { return Math.max(pos1.getBlockY(), pos2.getBlockY()); } - /** - * Expands the cuboid in a direction. - * - * @param change - */ + @Override public void expand(Vector... changes) { + checkNotNull(changes); + for (Vector change : changes) { if (change.getX() > 0) { if (Math.max(pos1.getX(), pos2.getX()) == pos1.getX()) { @@ -149,12 +225,10 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { recalculate(); } - /** - * Contracts the cuboid in a direction. - * - * @param change - */ + @Override public void contract(Vector... changes) { + checkNotNull(changes); + for (Vector change : changes) { if (change.getX() < 0) { if (Math.max(pos1.getX(), pos2.getX()) == pos1.getX()) { @@ -202,11 +276,6 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { recalculate(); } - private void recalculate() { - pos1 = pos1.clampY(0, world == null ? 255 : world.getMaxY()); - pos2 = pos2.clampY(0, world == null ? 255 : world.getMaxY()); - } - @Override public void shift(Vector change) throws RegionOperationException { pos1 = pos1.add(change); @@ -215,47 +284,7 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { recalculate(); } - /** - * Get position 1. - * - * @return position 1 - */ - public Vector getPos1() { - return pos1; - } - - /** - * Set position 1. - * - * @param pos1 - */ - public void setPos1(Vector pos1) { - this.pos1 = pos1; - } - - /** - * Get position 2. - * - * @return position 2 - */ - public Vector getPos2() { - return pos2; - } - - /** - * Set position 2. - * - * @param pos2 - */ - public void setPos2(Vector pos2) { - this.pos2 = pos2; - } - - /** - * Get a list of chunks that this region is within. - * - * @return - */ + @Override public Set getChunks() { Set chunks = new HashSet(); @@ -272,6 +301,7 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { return chunks; } + @Override public Set getChunkCubes() { Set chunks = new HashSet(); @@ -290,11 +320,7 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { return chunks; } - /** - * Returns true based on whether the region contains the point, - * - * @param pt - */ + @Override public boolean contains(Vector pt) { double x = pt.getX(); double y = pt.getY(); @@ -308,11 +334,6 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { && z >= min.getBlockZ() && z <= max.getBlockZ(); } - /** - * Get the iterator. - * - * @return iterator of points inside the region - */ @Override public Iterator iterator() { return new Iterator() { @@ -322,10 +343,12 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { private int nextY = min.getBlockY(); private int nextZ = min.getBlockZ(); + @Override public boolean hasNext() { return (nextX != Integer.MIN_VALUE); } + @Override public BlockVector next() { if (!hasNext()) throw new java.util.NoSuchElementException(); BlockVector answer = new BlockVector(nextX, nextY, nextZ); @@ -341,6 +364,7 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { return answer; } + @Override public void remove() { throw new UnsupportedOperationException(); } @@ -358,10 +382,12 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { private int nextX = min.getBlockX(); private int nextZ = min.getBlockZ(); + @Override public boolean hasNext() { return (nextX != Integer.MIN_VALUE); } + @Override public Vector2D next() { if (!hasNext()) throw new java.util.NoSuchElementException(); Vector2D answer = new Vector2D(nextX, nextZ); @@ -383,17 +409,12 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { }; } - /** - * Returns string representation in the format - * "(minX, minY, minZ) - (maxX, maxY, maxZ)". - * - * @return string - */ @Override public String toString() { return getMinimumPoint() + " - " + getMaximumPoint(); } + @Override public CuboidRegion clone() { return (CuboidRegion) super.clone(); } @@ -406,7 +427,21 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { * @return a new cuboid region */ public static CuboidRegion makeCuboid(Region region) { + checkNotNull(region); return new CuboidRegion(region.getMinimumPoint(), region.getMaximumPoint()); } + /** + * Make a cuboid from the center. + * + * @param origin the origin + * @param apothem the apothem, where 0 is the minimum value to make a 1x1 cuboid + * @return a cuboid region + */ + public static CuboidRegion fromCenter(Vector origin, int apothem) { + checkNotNull(origin); + checkArgument(apothem >= 0, "apothem => 0 required"); + Vector size = new Vector(1, 1, 1).multiply(apothem); + return new CuboidRegion(origin.subtract(size), origin.add(size)); + } } diff --git a/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java b/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java index 998c998db..b5af3708c 100644 --- a/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java +++ b/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java @@ -19,14 +19,13 @@ package com.sk89q.worldedit.regions; +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.regions.iterator.FlatRegion3DIterator; +import com.sk89q.worldedit.regions.iterator.FlatRegionIterator; + import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import com.sk89q.worldedit.BlockVector; -import com.sk89q.worldedit.BlockVector2D; -import com.sk89q.worldedit.LocalWorld; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.Vector2D; /** * Represents a cylindrical region. diff --git a/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java b/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java index 55c0688ff..cd990d570 100644 --- a/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java +++ b/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java @@ -24,7 +24,7 @@ import com.sk89q.worldedit.BlockVector2D; import com.sk89q.worldedit.LocalWorld; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector2D; -import com.sk89q.worldedit.data.ChunkStore; +import com.sk89q.worldedit.world.storage.ChunkStore; import java.util.Set; import java.util.HashSet; diff --git a/src/main/java/com/sk89q/worldedit/regions/NullRegion.java b/src/main/java/com/sk89q/worldedit/regions/NullRegion.java new file mode 100644 index 000000000..5a8ad3bde --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/NullRegion.java @@ -0,0 +1,139 @@ +/* + * 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.*; +import com.sk89q.worldedit.Vector; + +import java.util.*; + +/** + * A region that contains no points. + */ +public class NullRegion implements Region { + + private LocalWorld world; + + @Override + public Vector getMinimumPoint() { + return new Vector(0, 0, 0); + } + + @Override + public Vector getMaximumPoint() { + return new Vector(0, 0, 0); + } + + @Override + public Vector getCenter() { + return new Vector(0, 0, 0); + } + + @Override + public int getArea() { + return 0; + } + + @Override + public int getWidth() { + return 0; + } + + @Override + public int getHeight() { + return 0; + } + + @Override + public int getLength() { + return 0; + } + + @Override + public void expand(Vector... changes) throws RegionOperationException { + throw new RegionOperationException("Cannot change NullRegion"); + } + + @Override + public void contract(Vector... changes) throws RegionOperationException { + throw new RegionOperationException("Cannot change NullRegion"); + } + + @Override + public void shift(Vector change) throws RegionOperationException { + throw new RegionOperationException("Cannot change NullRegion"); + } + + @Override + public boolean contains(Vector pt) { + return false; + } + + @Override + public Set getChunks() { + return Collections.emptySet(); + } + + @Override + public Set getChunkCubes() { + return Collections.emptySet(); + } + + @Override + public LocalWorld getWorld() { + return world; + } + + @Override + public void setWorld(LocalWorld world) { + this.world = world; + } + + @Override + public NullRegion clone() { + return new NullRegion(); + } + + @Override + public List polygonize(int maxPoints) { + return Collections.emptyList(); + } + + @Override + public Iterator iterator() { + return new Iterator() { + @Override + public boolean hasNext() { + return false; + } + + @Override + public BlockVector next() { + throw new NoSuchElementException(); + } + + @Override + public void remove() { + throw new UnsupportedOperationException("Cannot remove"); + } + }; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/Polygonal2DRegion.java b/src/main/java/com/sk89q/worldedit/regions/Polygonal2DRegion.java index 0cfbb5d11..83b8e653d 100644 --- a/src/main/java/com/sk89q/worldedit/regions/Polygonal2DRegion.java +++ b/src/main/java/com/sk89q/worldedit/regions/Polygonal2DRegion.java @@ -28,6 +28,8 @@ import com.sk89q.worldedit.BlockVector2D; import com.sk89q.worldedit.LocalWorld; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.regions.iterator.FlatRegion3DIterator; +import com.sk89q.worldedit.regions.iterator.FlatRegionIterator; /** * Represents a 2D polygonal region. diff --git a/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java b/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java new file mode 100644 index 000000000..04cb256aa --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java @@ -0,0 +1,148 @@ +/* + * 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.google.common.collect.Iterators; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.Vector; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An intersection of several other regions. Any location that is contained in one + * of the child regions is considered as contained by this region. + *

+ * {@link #iterator()} returns a special iterator that will iterate through + * the iterators of each region in an undefined sequence. Some positions may + * be repeated if the position is contained in more than one region, but this cannot + * be guaranteed to occur. + */ +public class RegionIntersection extends AbstractRegion { + + private final List regions = new ArrayList(); + + /** + * Create a new instance with the included list of regions. + * + * @param regions a list of regions, which is copied + */ + public RegionIntersection(List regions) { + this(null, regions); + } + + /** + * Create a new instance with the included list of regions. + * + * @param regions a list of regions, which is copied + */ + public RegionIntersection(Region... regions) { + this(null, regions); + } + + /** + * Create a new instance with the included list of regions. + * + * @param world the world + * @param regions a list of regions, which is copied + */ + public RegionIntersection(LocalWorld world, List regions) { + super(world); + checkNotNull(regions); + checkArgument(regions.size() > 0, "empty region list is not supported"); + for (Region region : regions) { + this.regions.add(region); + } + } + + /** + * Create a new instance with the included list of regions. + * + * @param world the world + * @param regions an array of regions, which is copied + */ + public RegionIntersection(LocalWorld world, Region... regions) { + super(world); + checkNotNull(regions); + checkArgument(regions.length > 0, "empty region list is not supported"); + for (Region region : regions) { + this.regions.add(region); + } + } + + @Override + public Vector getMinimumPoint() { + Vector minimum = regions.get(0).getMinimumPoint(); + for (int i = 1; i < regions.size(); i++) { + minimum = Vector.getMinimum(regions.get(i).getMinimumPoint(), minimum); + } + return minimum; + } + + @Override + public Vector getMaximumPoint() { + Vector maximum = regions.get(0).getMaximumPoint(); + for (int i = 1; i < regions.size(); i++) { + maximum = Vector.getMaximum(regions.get(i).getMaximumPoint(), maximum); + } + return maximum; + } + + @Override + public void expand(Vector... changes) throws RegionOperationException { + checkNotNull(changes); + throw new RegionOperationException("Cannot expand a region intersection"); + } + + @Override + public void contract(Vector... changes) throws RegionOperationException { + checkNotNull(changes); + throw new RegionOperationException("Cannot contract a region intersection"); + } + + @Override + public boolean contains(Vector pt) { + checkNotNull(pt); + + for (Region region : regions) { + if (region.contains(pt)) { + return true; + } + } + + return false; + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + @Override + public Iterator iterator() { + Iterator[] iterators = (Iterator[]) new Iterator[regions.size()]; + for (int i = 0; i < regions.size(); i++) { + iterators[i] = regions.get(i).iterator(); + } + return Iterators.concat(iterators); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/Regions.java b/src/main/java/com/sk89q/worldedit/regions/Regions.java new file mode 100644 index 000000000..08bb58789 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/regions/Regions.java @@ -0,0 +1,92 @@ +/* + * 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; + +/** + * Utility methods relating to {@link Region}s. + */ +public final class Regions { + + private Regions() { + } + + /** + * Get the minimum Y coordinate of the given region using the region's + * {@link Region#getMinimumPoint()} method. + * + * @param region the region + * @return the Y coordinate + */ + public static double minimumY(Region region) { + return region.getMinimumPoint().getY(); + } + + /** + * Get the maximum Y coordinate of the given region using the region's + * {@link Region#getMaximumPoint()} method. + * + * @param region the region + * @return the Y coordinate + */ + public static double maximumY(Region region) { + return region.getMaximumPoint().getY(); + } + + /** + * Get the minimum Y coordinate of the given region using the region's + * {@link Region#getMinimumPoint()} method. + * + * @param region the region + * @return the Y coordinate + */ + public static int minimumBlockY(Region region) { + return region.getMinimumPoint().getBlockY(); + } + + /** + * Get the maximum Y coordinate of the given region using the region's + * {@link Region#getMaximumPoint()} method. + * + * @param region the region + * @return the Y coordinate + */ + public static int maximumBlockY(Region region) { + return region.getMaximumPoint().getBlockY(); + } + + /** + * Attempt to get a {@link FlatRegion} from the given region. + *

+ * If the given region is already a {@link FlatRegion}, then the region + * will be cast and returned. Otherwise, a new {@link CuboidRegion} will + * be created covers the provided region's minimum and maximum extents. + * + * @param region the region + * @return a flat region + */ + public static FlatRegion asFlatRegion(Region region) { + if (region instanceof FlatRegion) { + return (FlatRegion) region; + } else { + return CuboidRegion.makeCuboid(region); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/FlatRegion3DIterator.java b/src/main/java/com/sk89q/worldedit/regions/iterator/FlatRegion3DIterator.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/regions/FlatRegion3DIterator.java rename to src/main/java/com/sk89q/worldedit/regions/iterator/FlatRegion3DIterator.java index d365e248b..e22197c52 100644 --- a/src/main/java/com/sk89q/worldedit/regions/FlatRegion3DIterator.java +++ b/src/main/java/com/sk89q/worldedit/regions/iterator/FlatRegion3DIterator.java @@ -1,10 +1,11 @@ -package com.sk89q.worldedit.regions; +package com.sk89q.worldedit.regions.iterator; import java.util.Iterator; import java.util.NoSuchElementException; import com.sk89q.worldedit.BlockVector; import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.regions.FlatRegion; public class FlatRegion3DIterator implements Iterator { diff --git a/src/main/java/com/sk89q/worldedit/regions/FlatRegionIterator.java b/src/main/java/com/sk89q/worldedit/regions/iterator/FlatRegionIterator.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/regions/FlatRegionIterator.java rename to src/main/java/com/sk89q/worldedit/regions/iterator/FlatRegionIterator.java index ee56b0895..b9cd10e10 100644 --- a/src/main/java/com/sk89q/worldedit/regions/FlatRegionIterator.java +++ b/src/main/java/com/sk89q/worldedit/regions/iterator/FlatRegionIterator.java @@ -17,12 +17,13 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.regions; +package com.sk89q.worldedit.regions.iterator; import java.util.Iterator; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.regions.Region; public class FlatRegionIterator implements Iterator { diff --git a/src/main/java/com/sk89q/worldedit/regions/RegionIterator.java b/src/main/java/com/sk89q/worldedit/regions/iterator/RegionIterator.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/regions/RegionIterator.java rename to src/main/java/com/sk89q/worldedit/regions/iterator/RegionIterator.java index 8000af2d1..75274408e 100644 --- a/src/main/java/com/sk89q/worldedit/regions/RegionIterator.java +++ b/src/main/java/com/sk89q/worldedit/regions/iterator/RegionIterator.java @@ -1,94 +1,95 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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 java.util.Iterator; - -import com.sk89q.worldedit.BlockVector; -import com.sk89q.worldedit.Vector; - -public class RegionIterator implements Iterator { - private final Region region; - private final int maxX; - private final int maxY; - private final int maxZ; - private final Vector min; - private int nextX; - private int nextY; - private int nextZ; - - public RegionIterator(Region region) { - this.region = region; - - Vector max = region.getMaximumPoint(); - this.maxX = max.getBlockX(); - this.maxY = max.getBlockY(); - this.maxZ = max.getBlockZ(); - - this.min = region.getMinimumPoint(); - this.nextX = min.getBlockX(); - this.nextY = min.getBlockY(); - this.nextZ = min.getBlockZ(); - - forward(); - } - - public boolean hasNext() { - return nextX != Integer.MIN_VALUE; - } - - private void forward() { - while (hasNext() && !region.contains(new BlockVector(nextX, nextY, nextZ))) { - forwardOne(); - } - } - - public BlockVector next() { - if (!hasNext()) throw new java.util.NoSuchElementException(); - - BlockVector answer = new BlockVector(nextX, nextY, nextZ); - - forwardOne(); - forward(); - - return answer; - } - - private void forwardOne() { - if (++nextX <= maxX) { - return; - } - nextX = min.getBlockX(); - - if (++nextY <= maxY) { - return; - } - nextY = min.getBlockY(); - - if (++nextZ <= maxZ) { - return; - } - nextX = Integer.MIN_VALUE; - } - - public void remove() { - throw new UnsupportedOperationException(); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.iterator; + +import java.util.Iterator; + +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.regions.Region; + +public class RegionIterator implements Iterator { + private final Region region; + private final int maxX; + private final int maxY; + private final int maxZ; + private final Vector min; + private int nextX; + private int nextY; + private int nextZ; + + public RegionIterator(Region region) { + this.region = region; + + Vector max = region.getMaximumPoint(); + this.maxX = max.getBlockX(); + this.maxY = max.getBlockY(); + this.maxZ = max.getBlockZ(); + + this.min = region.getMinimumPoint(); + this.nextX = min.getBlockX(); + this.nextY = min.getBlockY(); + this.nextZ = min.getBlockZ(); + + forward(); + } + + public boolean hasNext() { + return nextX != Integer.MIN_VALUE; + } + + private void forward() { + while (hasNext() && !region.contains(new BlockVector(nextX, nextY, nextZ))) { + forwardOne(); + } + } + + public BlockVector next() { + if (!hasNext()) throw new java.util.NoSuchElementException(); + + BlockVector answer = new BlockVector(nextX, nextY, nextZ); + + forwardOne(); + forward(); + + return answer; + } + + private void forwardOne() { + if (++nextX <= maxX) { + return; + } + nextX = min.getBlockX(); + + if (++nextY <= maxY) { + return; + } + nextY = min.getBlockY(); + + if (++nextZ <= maxZ) { + return; + } + nextX = Integer.MIN_VALUE; + } + + public void remove() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/regions/ConvexPolyhedralRegionSelector.java b/src/main/java/com/sk89q/worldedit/regions/selector/ConvexPolyhedralRegionSelector.java similarity index 93% rename from src/main/java/com/sk89q/worldedit/regions/ConvexPolyhedralRegionSelector.java rename to src/main/java/com/sk89q/worldedit/regions/selector/ConvexPolyhedralRegionSelector.java index ba4d941ea..d28cef9dd 100644 --- a/src/main/java/com/sk89q/worldedit/regions/ConvexPolyhedralRegionSelector.java +++ b/src/main/java/com/sk89q/worldedit/regions/selector/ConvexPolyhedralRegionSelector.java @@ -1,219 +1,221 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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 java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import com.sk89q.worldedit.BlockVector; -import com.sk89q.worldedit.BlockVector2D; -import com.sk89q.worldedit.IncompleteRegionException; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.LocalWorld; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.cui.CUIRegion; -import com.sk89q.worldedit.cui.SelectionPointEvent; -import com.sk89q.worldedit.cui.SelectionPolygonEvent; -import com.sk89q.worldedit.cui.SelectionShapeEvent; -import com.sk89q.worldedit.regions.polyhedron.Triangle; - -public class ConvexPolyhedralRegionSelector implements RegionSelector, CUIRegion { - private int maxVertices; - private final ConvexPolyhedralRegion region; - private BlockVector pos1; - - public ConvexPolyhedralRegionSelector(LocalWorld world, int maxVertices) { - this.maxVertices = maxVertices; - region = new ConvexPolyhedralRegion(world); - } - - public ConvexPolyhedralRegionSelector(RegionSelector oldSelector, int maxVertices) { - this.maxVertices = maxVertices; - if (oldSelector instanceof ConvexPolyhedralRegionSelector) { - final ConvexPolyhedralRegionSelector convexPolyhedralRegionSelector = (ConvexPolyhedralRegionSelector) oldSelector; - - pos1 = convexPolyhedralRegionSelector.pos1; - region = new ConvexPolyhedralRegion(convexPolyhedralRegionSelector.region); - } else { - final Region oldRegion; - try { - oldRegion = oldSelector.getRegion(); - } catch (IncompleteRegionException e) { - region = new ConvexPolyhedralRegion(oldSelector.getIncompleteRegion().getWorld()); - return; - } - - final int minY = oldRegion.getMinimumPoint().getBlockY(); - final int maxY = oldRegion.getMaximumPoint().getBlockY(); - - region = new ConvexPolyhedralRegion(oldRegion.getWorld()); - - for (final BlockVector2D pt : new ArrayList(oldRegion.polygonize(maxVertices < 0 ? maxVertices : maxVertices / 2))) { - region.addVertex(pt.toVector(minY)); - region.addVertex(pt.toVector(maxY)); - } - - learnChanges(); - } - } - - @Override - public boolean selectPrimary(Vector pos) { - clear(); - pos1 = pos.toBlockVector(); - return region.addVertex(pos); - } - - @Override - public boolean selectSecondary(Vector pos) { - if (maxVertices >= 0 && region.getVertices().size() > maxVertices) { - return false; - } - - return region.addVertex(pos); - } - - @Override - public BlockVector getPrimaryPosition() throws IncompleteRegionException { - return pos1; - } - - @Override - public Region getRegion() throws IncompleteRegionException { - if (!region.isDefined()) { - throw new IncompleteRegionException(); - } - - return region; - } - - @Override - public Region getIncompleteRegion() { - return region; - } - - @Override - public boolean isDefined() { - return region.isDefined(); - } - - @Override - public int getArea() { - return region.getArea(); - } - - @Override - public void learnChanges() { - pos1 = region.getVertices().iterator().next().toBlockVector(); - } - - @Override - public void clear() { - region.clear(); - } - - @Override - public String getTypeName() { - return "Convex Polyhedron"; - } - - @Override - public List getInformationLines() { - List ret = new ArrayList(); - - ret.add("Vertices: "+region.getVertices().size()); - ret.add("Triangles: "+region.getTriangles().size()); - - return ret; - } - - - @Override - public void explainPrimarySelection(LocalPlayer player, LocalSession session, Vector pos) { - session.describeCUI(player); - - player.print("Started new selection with vertex "+pos+"."); - } - - @Override - public void explainSecondarySelection(LocalPlayer player, LocalSession session, Vector pos) { - session.describeCUI(player); - - player.print("Added vertex "+pos+" to the selection."); - } - - @Override - public void explainRegionAdjust(LocalPlayer player, LocalSession session) { - session.describeCUI(player); - } - - - @Override - public int getProtocolVersion() { - return 3; - } - - @Override - public String getTypeID() { - return "polyhedron"; - } - - @Override - public void describeCUI(LocalSession session, LocalPlayer player) { - Collection vertices = region.getVertices(); - Collection triangles = region.getTriangles(); - - player.dispatchCUIEvent(new SelectionShapeEvent(getTypeID())); - - Map vertexIds = new HashMap(vertices.size()); - int lastVertexId = -1; - for (Vector vertex : vertices) { - vertexIds.put(vertex, ++lastVertexId); - session.dispatchCUIEvent(player, new SelectionPointEvent(lastVertexId, vertex, getArea())); - } - - for (Triangle triangle : triangles) { - final int[] v = new int[3]; - for (int i = 0; i < 3; ++i) { - v[i] = vertexIds.get(triangle.getVertex(i)); - } - session.dispatchCUIEvent(player, new SelectionPolygonEvent(v)); - } - } - - @Override - public String getLegacyTypeID() { - return "cuboid"; - } - - @Override - public void describeLegacyCUI(LocalSession session, LocalPlayer player) { - if (isDefined()) { - session.dispatchCUIEvent(player, new SelectionPointEvent(0, region.getMinimumPoint(), getArea())); - session.dispatchCUIEvent(player, new SelectionPointEvent(1, region.getMaximumPoint(), getArea())); - } else { - session.dispatchCUIEvent(player, new SelectionShapeEvent(getLegacyTypeID())); - } - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.selector; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.BlockVector2D; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.internal.cui.CUIRegion; +import com.sk89q.worldedit.internal.cui.SelectionPointEvent; +import com.sk89q.worldedit.internal.cui.SelectionPolygonEvent; +import com.sk89q.worldedit.internal.cui.SelectionShapeEvent; +import com.sk89q.worldedit.regions.ConvexPolyhedralRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.polyhedron.Triangle; + +public class ConvexPolyhedralRegionSelector implements RegionSelector, CUIRegion { + private int maxVertices; + private final ConvexPolyhedralRegion region; + private BlockVector pos1; + + public ConvexPolyhedralRegionSelector(LocalWorld world, int maxVertices) { + this.maxVertices = maxVertices; + region = new ConvexPolyhedralRegion(world); + } + + public ConvexPolyhedralRegionSelector(RegionSelector oldSelector, int maxVertices) { + this.maxVertices = maxVertices; + if (oldSelector instanceof ConvexPolyhedralRegionSelector) { + final ConvexPolyhedralRegionSelector convexPolyhedralRegionSelector = (ConvexPolyhedralRegionSelector) oldSelector; + + pos1 = convexPolyhedralRegionSelector.pos1; + region = new ConvexPolyhedralRegion(convexPolyhedralRegionSelector.region); + } else { + final Region oldRegion; + try { + oldRegion = oldSelector.getRegion(); + } catch (IncompleteRegionException e) { + region = new ConvexPolyhedralRegion(oldSelector.getIncompleteRegion().getWorld()); + return; + } + + final int minY = oldRegion.getMinimumPoint().getBlockY(); + final int maxY = oldRegion.getMaximumPoint().getBlockY(); + + region = new ConvexPolyhedralRegion(oldRegion.getWorld()); + + for (final BlockVector2D pt : new ArrayList(oldRegion.polygonize(maxVertices < 0 ? maxVertices : maxVertices / 2))) { + region.addVertex(pt.toVector(minY)); + region.addVertex(pt.toVector(maxY)); + } + + learnChanges(); + } + } + + @Override + public boolean selectPrimary(Vector pos) { + clear(); + pos1 = pos.toBlockVector(); + return region.addVertex(pos); + } + + @Override + public boolean selectSecondary(Vector pos) { + if (maxVertices >= 0 && region.getVertices().size() > maxVertices) { + return false; + } + + return region.addVertex(pos); + } + + @Override + public BlockVector getPrimaryPosition() throws IncompleteRegionException { + return pos1; + } + + @Override + public Region getRegion() throws IncompleteRegionException { + if (!region.isDefined()) { + throw new IncompleteRegionException(); + } + + return region; + } + + @Override + public Region getIncompleteRegion() { + return region; + } + + @Override + public boolean isDefined() { + return region.isDefined(); + } + + @Override + public int getArea() { + return region.getArea(); + } + + @Override + public void learnChanges() { + pos1 = region.getVertices().iterator().next().toBlockVector(); + } + + @Override + public void clear() { + region.clear(); + } + + @Override + public String getTypeName() { + return "Convex Polyhedron"; + } + + @Override + public List getInformationLines() { + List ret = new ArrayList(); + + ret.add("Vertices: "+region.getVertices().size()); + ret.add("Triangles: "+region.getTriangles().size()); + + return ret; + } + + + @Override + public void explainPrimarySelection(LocalPlayer player, LocalSession session, Vector pos) { + session.describeCUI(player); + + player.print("Started new selection with vertex "+pos+"."); + } + + @Override + public void explainSecondarySelection(LocalPlayer player, LocalSession session, Vector pos) { + session.describeCUI(player); + + player.print("Added vertex "+pos+" to the selection."); + } + + @Override + public void explainRegionAdjust(LocalPlayer player, LocalSession session) { + session.describeCUI(player); + } + + + @Override + public int getProtocolVersion() { + return 3; + } + + @Override + public String getTypeID() { + return "polyhedron"; + } + + @Override + public void describeCUI(LocalSession session, LocalPlayer player) { + Collection vertices = region.getVertices(); + Collection triangles = region.getTriangles(); + + player.dispatchCUIEvent(new SelectionShapeEvent(getTypeID())); + + Map vertexIds = new HashMap(vertices.size()); + int lastVertexId = -1; + for (Vector vertex : vertices) { + vertexIds.put(vertex, ++lastVertexId); + session.dispatchCUIEvent(player, new SelectionPointEvent(lastVertexId, vertex, getArea())); + } + + for (Triangle triangle : triangles) { + final int[] v = new int[3]; + for (int i = 0; i < 3; ++i) { + v[i] = vertexIds.get(triangle.getVertex(i)); + } + session.dispatchCUIEvent(player, new SelectionPolygonEvent(v)); + } + } + + @Override + public String getLegacyTypeID() { + return "cuboid"; + } + + @Override + public void describeLegacyCUI(LocalSession session, LocalPlayer player) { + if (isDefined()) { + session.dispatchCUIEvent(player, new SelectionPointEvent(0, region.getMinimumPoint(), getArea())); + session.dispatchCUIEvent(player, new SelectionPointEvent(1, region.getMaximumPoint(), getArea())); + } else { + session.dispatchCUIEvent(player, new SelectionShapeEvent(getLegacyTypeID())); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/regions/CuboidRegionSelector.java b/src/main/java/com/sk89q/worldedit/regions/selector/CuboidRegionSelector.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/regions/CuboidRegionSelector.java rename to src/main/java/com/sk89q/worldedit/regions/selector/CuboidRegionSelector.java index 229239dbf..c5494e141 100644 --- a/src/main/java/com/sk89q/worldedit/regions/CuboidRegionSelector.java +++ b/src/main/java/com/sk89q/worldedit/regions/selector/CuboidRegionSelector.java @@ -1,223 +1,225 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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 java.util.ArrayList; -import java.util.List; -import com.sk89q.worldedit.BlockVector; -import com.sk89q.worldedit.IncompleteRegionException; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.LocalWorld; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.cui.CUIRegion; -import com.sk89q.worldedit.cui.SelectionPointEvent; - -/** - * Selector for cuboids. - * - * @author sk89q - */ -public class CuboidRegionSelector implements RegionSelector, CUIRegion { - protected BlockVector pos1; - protected BlockVector pos2; - protected CuboidRegion region; - - public CuboidRegionSelector(LocalWorld world) { - region = new CuboidRegion(world, new Vector(), new Vector()); - } - - public CuboidRegionSelector() { - this((LocalWorld) null); - } - - public CuboidRegionSelector(RegionSelector oldSelector) { - this(oldSelector.getIncompleteRegion().getWorld()); - if (oldSelector instanceof CuboidRegionSelector) { - final CuboidRegionSelector cuboidRegionSelector = (CuboidRegionSelector) oldSelector; - - pos1 = cuboidRegionSelector.pos1; - pos2 = cuboidRegionSelector.pos2; - } else { - final Region oldRegion; - try { - oldRegion = oldSelector.getRegion(); - } catch (IncompleteRegionException e) { - return; - } - - pos1 = oldRegion.getMinimumPoint().toBlockVector(); - pos2 = oldRegion.getMaximumPoint().toBlockVector(); - } - - region.setPos1(pos1); - region.setPos2(pos2); - } - - public CuboidRegionSelector(LocalWorld world, Vector pos1, Vector pos2) { - this(world); - this.pos1 = pos1.toBlockVector(); - this.pos2 = pos2.toBlockVector(); - region.setPos1(pos1); - region.setPos2(pos2); - } - - public boolean selectPrimary(Vector pos) { - if (pos1 != null && (pos.compareTo(pos1) == 0)) { - return false; - } - - pos1 = pos.toBlockVector(); - region.setPos1(pos1); - return true; - } - - public boolean selectSecondary(Vector pos) { - if (pos2 != null && (pos.compareTo(pos2)) == 0) { - return false; - } - - pos2 = pos.toBlockVector(); - region.setPos2(pos2); - return true; - } - - public void explainPrimarySelection(LocalPlayer player, LocalSession session, Vector pos) { - if (pos1 != null && pos2 != null) { - player.print("First position set to " + pos1 + " (" + region.getArea() + ")."); - } else { - player.print("First position set to " + pos1 + "."); - } - - session.dispatchCUIEvent(player, new SelectionPointEvent(0, pos, getArea())); - } - - public void explainSecondarySelection(LocalPlayer player, LocalSession session, Vector pos) { - if (pos1 != null && pos2 != null) { - player.print("Second position set to " + pos2 + " (" + region.getArea() + ")."); - } else { - player.print("Second position set to " + pos2 + "."); - } - - session.dispatchCUIEvent(player, new SelectionPointEvent(1, pos, getArea())); - } - - public void explainRegionAdjust(LocalPlayer player, LocalSession session) { - if (pos1 != null) { - session.dispatchCUIEvent(player, new SelectionPointEvent(0, pos1, getArea())); - } - - if (pos2 != null) { - session.dispatchCUIEvent(player, new SelectionPointEvent(1, pos2, getArea())); - } - } - - public BlockVector getPrimaryPosition() throws IncompleteRegionException { - if (pos1 == null) { - throw new IncompleteRegionException(); - } - - return pos1; - } - - public boolean isDefined() { - return pos1 != null && pos2 != null; - } - - public CuboidRegion getRegion() throws IncompleteRegionException { - if (pos1 == null || pos2 == null) { - throw new IncompleteRegionException(); - } - - return region; - } - - public CuboidRegion getIncompleteRegion() { - return region; - } - - public void learnChanges() { - pos1 = region.getPos1().toBlockVector(); - pos2 = region.getPos2().toBlockVector(); - } - - public void clear() { - pos1 = null; - pos2 = null; - } - - public String getTypeName() { - return "cuboid"; - } - - public List getInformationLines() { - final List lines = new ArrayList(); - - if (pos1 != null) { - lines.add("Position 1: " + pos1); - } - - if (pos2 != null) { - lines.add("Position 2: " + pos2); - } - - return lines; - } - - public int getArea() { - if (pos1 == null) { - return -1; - } - - if (pos2 == null) { - return -1; - } - - return region.getArea(); - } - - public void describeCUI(LocalSession session, LocalPlayer player) { - if (pos1 != null) { - session.dispatchCUIEvent(player, new SelectionPointEvent(0, pos1, getArea())); - } - - if (pos2 != null) { - session.dispatchCUIEvent(player, new SelectionPointEvent(1, pos2, getArea())); - } - } - - public void describeLegacyCUI(LocalSession session, LocalPlayer player) { - describeCUI(session, player); - } - - public int getProtocolVersion() { - return 0; - } - - public String getTypeID() { - return "cuboid"; - } - - public String getLegacyTypeID() { - return "cuboid"; - } - - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.selector; + +import java.util.ArrayList; +import java.util.List; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.internal.cui.CUIRegion; +import com.sk89q.worldedit.internal.cui.SelectionPointEvent; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; + +/** + * Selector for cuboids. + * + * @author sk89q + */ +public class CuboidRegionSelector implements RegionSelector, CUIRegion { + protected BlockVector pos1; + protected BlockVector pos2; + protected CuboidRegion region; + + public CuboidRegionSelector(LocalWorld world) { + region = new CuboidRegion(world, new Vector(), new Vector()); + } + + public CuboidRegionSelector() { + this((LocalWorld) null); + } + + public CuboidRegionSelector(RegionSelector oldSelector) { + this(oldSelector.getIncompleteRegion().getWorld()); + if (oldSelector instanceof CuboidRegionSelector) { + final CuboidRegionSelector cuboidRegionSelector = (CuboidRegionSelector) oldSelector; + + pos1 = cuboidRegionSelector.pos1; + pos2 = cuboidRegionSelector.pos2; + } else { + final Region oldRegion; + try { + oldRegion = oldSelector.getRegion(); + } catch (IncompleteRegionException e) { + return; + } + + pos1 = oldRegion.getMinimumPoint().toBlockVector(); + pos2 = oldRegion.getMaximumPoint().toBlockVector(); + } + + region.setPos1(pos1); + region.setPos2(pos2); + } + + public CuboidRegionSelector(LocalWorld world, Vector pos1, Vector pos2) { + this(world); + this.pos1 = pos1.toBlockVector(); + this.pos2 = pos2.toBlockVector(); + region.setPos1(pos1); + region.setPos2(pos2); + } + + public boolean selectPrimary(Vector pos) { + if (pos1 != null && (pos.compareTo(pos1) == 0)) { + return false; + } + + pos1 = pos.toBlockVector(); + region.setPos1(pos1); + return true; + } + + public boolean selectSecondary(Vector pos) { + if (pos2 != null && (pos.compareTo(pos2)) == 0) { + return false; + } + + pos2 = pos.toBlockVector(); + region.setPos2(pos2); + return true; + } + + public void explainPrimarySelection(LocalPlayer player, LocalSession session, Vector pos) { + if (pos1 != null && pos2 != null) { + player.print("First position set to " + pos1 + " (" + region.getArea() + ")."); + } else { + player.print("First position set to " + pos1 + "."); + } + + session.dispatchCUIEvent(player, new SelectionPointEvent(0, pos, getArea())); + } + + public void explainSecondarySelection(LocalPlayer player, LocalSession session, Vector pos) { + if (pos1 != null && pos2 != null) { + player.print("Second position set to " + pos2 + " (" + region.getArea() + ")."); + } else { + player.print("Second position set to " + pos2 + "."); + } + + session.dispatchCUIEvent(player, new SelectionPointEvent(1, pos, getArea())); + } + + public void explainRegionAdjust(LocalPlayer player, LocalSession session) { + if (pos1 != null) { + session.dispatchCUIEvent(player, new SelectionPointEvent(0, pos1, getArea())); + } + + if (pos2 != null) { + session.dispatchCUIEvent(player, new SelectionPointEvent(1, pos2, getArea())); + } + } + + public BlockVector getPrimaryPosition() throws IncompleteRegionException { + if (pos1 == null) { + throw new IncompleteRegionException(); + } + + return pos1; + } + + public boolean isDefined() { + return pos1 != null && pos2 != null; + } + + public CuboidRegion getRegion() throws IncompleteRegionException { + if (pos1 == null || pos2 == null) { + throw new IncompleteRegionException(); + } + + return region; + } + + public CuboidRegion getIncompleteRegion() { + return region; + } + + public void learnChanges() { + pos1 = region.getPos1().toBlockVector(); + pos2 = region.getPos2().toBlockVector(); + } + + public void clear() { + pos1 = null; + pos2 = null; + } + + public String getTypeName() { + return "cuboid"; + } + + public List getInformationLines() { + final List lines = new ArrayList(); + + if (pos1 != null) { + lines.add("Position 1: " + pos1); + } + + if (pos2 != null) { + lines.add("Position 2: " + pos2); + } + + return lines; + } + + public int getArea() { + if (pos1 == null) { + return -1; + } + + if (pos2 == null) { + return -1; + } + + return region.getArea(); + } + + public void describeCUI(LocalSession session, LocalPlayer player) { + if (pos1 != null) { + session.dispatchCUIEvent(player, new SelectionPointEvent(0, pos1, getArea())); + } + + if (pos2 != null) { + session.dispatchCUIEvent(player, new SelectionPointEvent(1, pos2, getArea())); + } + } + + public void describeLegacyCUI(LocalSession session, LocalPlayer player) { + describeCUI(session, player); + } + + public int getProtocolVersion() { + return 0; + } + + public String getTypeID() { + return "cuboid"; + } + + public String getLegacyTypeID() { + return "cuboid"; + } + + +} diff --git a/src/main/java/com/sk89q/worldedit/regions/CylinderRegionSelector.java b/src/main/java/com/sk89q/worldedit/regions/selector/CylinderRegionSelector.java similarity index 93% rename from src/main/java/com/sk89q/worldedit/regions/CylinderRegionSelector.java rename to src/main/java/com/sk89q/worldedit/regions/selector/CylinderRegionSelector.java index 54585f708..316e04c0e 100644 --- a/src/main/java/com/sk89q/worldedit/regions/CylinderRegionSelector.java +++ b/src/main/java/com/sk89q/worldedit/regions/selector/CylinderRegionSelector.java @@ -1,218 +1,221 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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 java.util.ArrayList; -import java.util.List; -import com.sk89q.worldedit.BlockVector; -import com.sk89q.worldedit.IncompleteRegionException; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.LocalWorld; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.Vector2D; -import com.sk89q.worldedit.cui.CUIRegion; -import com.sk89q.worldedit.cui.SelectionCylinderEvent; -import com.sk89q.worldedit.cui.SelectionMinMaxEvent; -import com.sk89q.worldedit.cui.SelectionPointEvent; -import com.sk89q.worldedit.cui.SelectionShapeEvent; -import java.text.NumberFormat; - -/** - * Selector for polygonal regions. - * - * @author sk89q - */ -public class CylinderRegionSelector implements RegionSelector, CUIRegion { - protected CylinderRegion region; - protected static final NumberFormat format; - - static { - format = (NumberFormat) NumberFormat.getInstance().clone(); - format.setMaximumFractionDigits(3); - } - - public CylinderRegionSelector(LocalWorld world) { - region = new CylinderRegion(world); - } - - public CylinderRegionSelector(RegionSelector oldSelector) { - this(oldSelector.getIncompleteRegion().getWorld()); - if (oldSelector instanceof CylinderRegionSelector) { - final CylinderRegionSelector cylSelector = (CylinderRegionSelector) oldSelector; - - region = new CylinderRegion(cylSelector.region); - } else { - final Region oldRegion; - try { - oldRegion = oldSelector.getRegion(); - } catch (IncompleteRegionException e) { - return; - } - - Vector pos1 = oldRegion.getMinimumPoint(); - Vector pos2 = oldRegion.getMaximumPoint(); - - Vector center = pos1.add(pos2).divide(2).floor(); - region.setCenter(center.toVector2D()); - region.setRadius(pos2.toVector2D().subtract(center.toVector2D())); - - region.setMaximumY(Math.max(pos1.getBlockY(), pos2.getBlockY())); - region.setMinimumY(Math.min(pos1.getBlockY(), pos2.getBlockY())); - } - } - - public CylinderRegionSelector(LocalWorld world, Vector2D center, Vector2D radius, int minY, int maxY) { - this(world); - - region.setCenter(center); - region.setRadius(radius); - - region.setMinimumY(Math.min(minY, maxY)); - region.setMaximumY(Math.max(minY, maxY)); - } - - public boolean selectPrimary(Vector pos) { - if (!region.getCenter().equals(Vector.ZERO) && pos.compareTo(region.getCenter()) == 0) { - return false; - } - - region = new CylinderRegion(region.getWorld()); - region.setCenter(pos.toVector2D()); - region.setY(pos.getBlockY()); - - return true; - } - - public boolean selectSecondary(Vector pos) { - Vector center = region.getCenter(); - if ((center.compareTo(Vector.ZERO)) == 0) { - return true; - } - - final Vector2D diff = pos.subtract(center).toVector2D(); - final Vector2D minRadius = Vector2D.getMaximum(diff, diff.multiply(-1.0)); - region.extendRadius(minRadius); - - region.setY(pos.getBlockY()); - - return true; - } - - public void explainPrimarySelection(LocalPlayer player, LocalSession session, Vector pos) { - player.print("Starting a new cylindrical selection at " + pos + "."); - - session.describeCUI(player); - } - - public void explainSecondarySelection(LocalPlayer player, LocalSession session, Vector pos) { - Vector center = region.getCenter(); - if (!center.equals(Vector.ZERO)) { - player.print("Radius set to " + format.format(region.getRadius().getX()) + "/" + format.format(region.getRadius().getZ()) + " blocks. (" + region.getArea() + ")."); - } else { - player.printError("You must select the center point before setting the radius."); - return; - } - - session.describeCUI(player); - } - - public void explainRegionAdjust(LocalPlayer player, LocalSession session) { - session.describeCUI(player); - } - - public BlockVector getPrimaryPosition() throws IncompleteRegionException { - if (!isDefined()) { - throw new IncompleteRegionException(); - } - - return region.getCenter().toBlockVector(); - } - - public CylinderRegion getRegion() throws IncompleteRegionException { - if (!isDefined()) { - throw new IncompleteRegionException(); - } - - return region; - } - - public CylinderRegion getIncompleteRegion() { - return region; - } - - public boolean isDefined() { - return !region.getRadius().equals(Vector2D.ZERO); - } - - public void learnChanges() { - } - - public void clear() { - region = new CylinderRegion(region.getWorld()); - } - - public String getTypeName() { - return "Cylinder"; - } - - public List getInformationLines() { - final List lines = new ArrayList(); - - if (!region.getCenter().equals(Vector.ZERO)) { - lines.add("Center: " + region.getCenter()); - } - if (!region.getRadius().equals(Vector2D.ZERO)) { - lines.add("Radius: " + region.getRadius()); - } - - return lines; - } - - public int getArea() { - return region.getArea(); - } - - public void describeCUI(LocalSession session, LocalPlayer player) { - session.dispatchCUIEvent(player, new SelectionCylinderEvent(region.getCenter(), region.getRadius())); - session.dispatchCUIEvent(player, new SelectionMinMaxEvent(region.getMinimumY(), region.getMaximumY())); - } - - public void describeLegacyCUI(LocalSession session, LocalPlayer player) { - if (isDefined()) { - session.dispatchCUIEvent(player, new SelectionPointEvent(0, region.getMinimumPoint(), getArea())); - session.dispatchCUIEvent(player, new SelectionPointEvent(1, region.getMaximumPoint(), getArea())); - } else { - session.dispatchCUIEvent(player, new SelectionShapeEvent(getLegacyTypeID())); - } - } - - public int getProtocolVersion() { - return 1; - } - - public String getTypeID() { - return "cylinder"; - } - - public String getLegacyTypeID() { - return "cuboid"; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.selector; + +import java.util.ArrayList; +import java.util.List; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.internal.cui.CUIRegion; +import com.sk89q.worldedit.internal.cui.SelectionCylinderEvent; +import com.sk89q.worldedit.internal.cui.SelectionMinMaxEvent; +import com.sk89q.worldedit.internal.cui.SelectionPointEvent; +import com.sk89q.worldedit.internal.cui.SelectionShapeEvent; +import com.sk89q.worldedit.regions.CylinderRegion; +import com.sk89q.worldedit.regions.Region; + +import java.text.NumberFormat; + +/** + * Selector for polygonal regions. + * + * @author sk89q + */ +public class CylinderRegionSelector implements RegionSelector, CUIRegion { + protected CylinderRegion region; + protected static final NumberFormat format; + + static { + format = (NumberFormat) NumberFormat.getInstance().clone(); + format.setMaximumFractionDigits(3); + } + + public CylinderRegionSelector(LocalWorld world) { + region = new CylinderRegion(world); + } + + public CylinderRegionSelector(RegionSelector oldSelector) { + this(oldSelector.getIncompleteRegion().getWorld()); + if (oldSelector instanceof CylinderRegionSelector) { + final CylinderRegionSelector cylSelector = (CylinderRegionSelector) oldSelector; + + region = new CylinderRegion(cylSelector.region); + } else { + final Region oldRegion; + try { + oldRegion = oldSelector.getRegion(); + } catch (IncompleteRegionException e) { + return; + } + + Vector pos1 = oldRegion.getMinimumPoint(); + Vector pos2 = oldRegion.getMaximumPoint(); + + Vector center = pos1.add(pos2).divide(2).floor(); + region.setCenter(center.toVector2D()); + region.setRadius(pos2.toVector2D().subtract(center.toVector2D())); + + region.setMaximumY(Math.max(pos1.getBlockY(), pos2.getBlockY())); + region.setMinimumY(Math.min(pos1.getBlockY(), pos2.getBlockY())); + } + } + + public CylinderRegionSelector(LocalWorld world, Vector2D center, Vector2D radius, int minY, int maxY) { + this(world); + + region.setCenter(center); + region.setRadius(radius); + + region.setMinimumY(Math.min(minY, maxY)); + region.setMaximumY(Math.max(minY, maxY)); + } + + public boolean selectPrimary(Vector pos) { + if (!region.getCenter().equals(Vector.ZERO) && pos.compareTo(region.getCenter()) == 0) { + return false; + } + + region = new CylinderRegion(region.getWorld()); + region.setCenter(pos.toVector2D()); + region.setY(pos.getBlockY()); + + return true; + } + + public boolean selectSecondary(Vector pos) { + Vector center = region.getCenter(); + if ((center.compareTo(Vector.ZERO)) == 0) { + return true; + } + + final Vector2D diff = pos.subtract(center).toVector2D(); + final Vector2D minRadius = Vector2D.getMaximum(diff, diff.multiply(-1.0)); + region.extendRadius(minRadius); + + region.setY(pos.getBlockY()); + + return true; + } + + public void explainPrimarySelection(LocalPlayer player, LocalSession session, Vector pos) { + player.print("Starting a new cylindrical selection at " + pos + "."); + + session.describeCUI(player); + } + + public void explainSecondarySelection(LocalPlayer player, LocalSession session, Vector pos) { + Vector center = region.getCenter(); + if (!center.equals(Vector.ZERO)) { + player.print("Radius set to " + format.format(region.getRadius().getX()) + "/" + format.format(region.getRadius().getZ()) + " blocks. (" + region.getArea() + ")."); + } else { + player.printError("You must select the center point before setting the radius."); + return; + } + + session.describeCUI(player); + } + + public void explainRegionAdjust(LocalPlayer player, LocalSession session) { + session.describeCUI(player); + } + + public BlockVector getPrimaryPosition() throws IncompleteRegionException { + if (!isDefined()) { + throw new IncompleteRegionException(); + } + + return region.getCenter().toBlockVector(); + } + + public CylinderRegion getRegion() throws IncompleteRegionException { + if (!isDefined()) { + throw new IncompleteRegionException(); + } + + return region; + } + + public CylinderRegion getIncompleteRegion() { + return region; + } + + public boolean isDefined() { + return !region.getRadius().equals(Vector2D.ZERO); + } + + public void learnChanges() { + } + + public void clear() { + region = new CylinderRegion(region.getWorld()); + } + + public String getTypeName() { + return "Cylinder"; + } + + public List getInformationLines() { + final List lines = new ArrayList(); + + if (!region.getCenter().equals(Vector.ZERO)) { + lines.add("Center: " + region.getCenter()); + } + if (!region.getRadius().equals(Vector2D.ZERO)) { + lines.add("Radius: " + region.getRadius()); + } + + return lines; + } + + public int getArea() { + return region.getArea(); + } + + public void describeCUI(LocalSession session, LocalPlayer player) { + session.dispatchCUIEvent(player, new SelectionCylinderEvent(region.getCenter(), region.getRadius())); + session.dispatchCUIEvent(player, new SelectionMinMaxEvent(region.getMinimumY(), region.getMaximumY())); + } + + public void describeLegacyCUI(LocalSession session, LocalPlayer player) { + if (isDefined()) { + session.dispatchCUIEvent(player, new SelectionPointEvent(0, region.getMinimumPoint(), getArea())); + session.dispatchCUIEvent(player, new SelectionPointEvent(1, region.getMaximumPoint(), getArea())); + } else { + session.dispatchCUIEvent(player, new SelectionShapeEvent(getLegacyTypeID())); + } + } + + public int getProtocolVersion() { + return 1; + } + + public String getTypeID() { + return "cylinder"; + } + + public String getLegacyTypeID() { + return "cuboid"; + } +} diff --git a/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegionSelector.java b/src/main/java/com/sk89q/worldedit/regions/selector/EllipsoidRegionSelector.java similarity index 93% rename from src/main/java/com/sk89q/worldedit/regions/EllipsoidRegionSelector.java rename to src/main/java/com/sk89q/worldedit/regions/selector/EllipsoidRegionSelector.java index 8a84ac8e7..0db43366b 100644 --- a/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegionSelector.java +++ b/src/main/java/com/sk89q/worldedit/regions/selector/EllipsoidRegionSelector.java @@ -1,195 +1,197 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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 java.util.ArrayList; -import java.util.List; -import com.sk89q.worldedit.BlockVector; -import com.sk89q.worldedit.IncompleteRegionException; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.LocalWorld; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.cui.CUIRegion; -import com.sk89q.worldedit.cui.SelectionEllipsoidPointEvent; -import com.sk89q.worldedit.cui.SelectionPointEvent; - -/** - * Selector for ellipsoids. - * - * @author TomyLobo - */ -public class EllipsoidRegionSelector implements RegionSelector, CUIRegion { - protected EllipsoidRegion region; - - public EllipsoidRegionSelector(LocalWorld world) { - region = new EllipsoidRegion(world, new Vector(), new Vector()); - } - - public EllipsoidRegionSelector() { - this((LocalWorld) null); - } - - public EllipsoidRegionSelector(RegionSelector oldSelector) { - this(oldSelector.getIncompleteRegion().getWorld()); - if (oldSelector instanceof EllipsoidRegionSelector) { - final EllipsoidRegionSelector ellipsoidRegionSelector = (EllipsoidRegionSelector) oldSelector; - - region = new EllipsoidRegion(ellipsoidRegionSelector.getIncompleteRegion()); - } else { - Region oldRegion = null; - try { - oldRegion = oldSelector.getRegion(); - } catch (IncompleteRegionException e) { - return; - } - - BlockVector pos1 = oldRegion.getMinimumPoint().toBlockVector(); - BlockVector pos2 = oldRegion.getMaximumPoint().toBlockVector(); - - Vector center = pos1.add(pos2).divide(2).floor(); - region.setCenter(center); - region.setRadius(pos2.subtract(center)); - } - } - - public EllipsoidRegionSelector(LocalWorld world, Vector center, Vector radius) { - this(world); - - region.setCenter(center); - region.setRadius(radius); - } - - public boolean selectPrimary(Vector pos) { - if (pos.equals(region.getCenter()) && region.getRadius().lengthSq() == 0) { - return false; - } - - region.setCenter(pos.toBlockVector()); - region.setRadius(new Vector()); - return true; - } - - public boolean selectSecondary(Vector pos) { - final Vector diff = pos.subtract(region.getCenter()); - final Vector minRadius = Vector.getMaximum(diff, diff.multiply(-1.0)); - region.extendRadius(minRadius); - return true; - } - - public void explainPrimarySelection(LocalPlayer player, LocalSession session, Vector pos) { - if (isDefined()) { - player.print("Center position set to " + region.getCenter() + " (" + region.getArea() + ")."); - } else { - player.print("Center position set to " + region.getCenter() + "."); - } - - session.describeCUI(player); - } - - public void explainSecondarySelection(LocalPlayer player, LocalSession session, Vector pos) { - if (isDefined()) { - player.print("Radius set to " + region.getRadius() + " (" + region.getArea() + ")."); - } else { - player.print("Radius set to " + region.getRadius() + "."); - } - - session.describeCUI(player); - } - - public void explainRegionAdjust(LocalPlayer player, LocalSession session) { - session.describeCUI(player); - } - - public boolean isDefined() { - return region.getRadius().lengthSq() > 0; - } - - public EllipsoidRegion getRegion() throws IncompleteRegionException { - if (!isDefined()) { - throw new IncompleteRegionException(); - } - - return region; - } - - public EllipsoidRegion getIncompleteRegion() { - return region; - } - - public void learnChanges() { - } - - public void clear() { - region.setCenter(new Vector()); - region.setRadius(new Vector()); - } - - public String getTypeName() { - return "ellipsoid"; - } - - public List getInformationLines() { - final List lines = new ArrayList(); - - final Vector center = region.getCenter(); - if (center.lengthSq() > 0) { - lines.add("Center: " + center); - } - - final Vector radius = region.getRadius(); - if (radius.lengthSq() > 0) { - lines.add("X/Y/Z radius: " + radius); - } - - return lines; - } - - public int getArea() { - return region.getArea(); - } - - public void describeCUI(LocalSession session, LocalPlayer player) { - session.dispatchCUIEvent(player, new SelectionEllipsoidPointEvent(0, region.getCenter())); - session.dispatchCUIEvent(player, new SelectionEllipsoidPointEvent(1, region.getRadius())); - } - - public void describeLegacyCUI(LocalSession session, LocalPlayer player) { - session.dispatchCUIEvent(player, new SelectionPointEvent(0, region.getMinimumPoint(), getArea())); - session.dispatchCUIEvent(player, new SelectionPointEvent(1, region.getMaximumPoint(), getArea())); - } - - public String getLegacyTypeID() { - return "cuboid"; - } - - public int getProtocolVersion() { - return 1; - } - - public String getTypeID() { - return "ellipsoid"; - } - - @Override - public BlockVector getPrimaryPosition() throws IncompleteRegionException { - return region.getCenter().toBlockVector(); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.selector; + +import java.util.ArrayList; +import java.util.List; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.internal.cui.CUIRegion; +import com.sk89q.worldedit.internal.cui.SelectionEllipsoidPointEvent; +import com.sk89q.worldedit.internal.cui.SelectionPointEvent; +import com.sk89q.worldedit.regions.EllipsoidRegion; +import com.sk89q.worldedit.regions.Region; + +/** + * Selector for ellipsoids. + * + * @author TomyLobo + */ +public class EllipsoidRegionSelector implements RegionSelector, CUIRegion { + protected EllipsoidRegion region; + + public EllipsoidRegionSelector(LocalWorld world) { + region = new EllipsoidRegion(world, new Vector(), new Vector()); + } + + public EllipsoidRegionSelector() { + this((LocalWorld) null); + } + + public EllipsoidRegionSelector(RegionSelector oldSelector) { + this(oldSelector.getIncompleteRegion().getWorld()); + if (oldSelector instanceof EllipsoidRegionSelector) { + final EllipsoidRegionSelector ellipsoidRegionSelector = (EllipsoidRegionSelector) oldSelector; + + region = new EllipsoidRegion(ellipsoidRegionSelector.getIncompleteRegion()); + } else { + Region oldRegion = null; + try { + oldRegion = oldSelector.getRegion(); + } catch (IncompleteRegionException e) { + return; + } + + BlockVector pos1 = oldRegion.getMinimumPoint().toBlockVector(); + BlockVector pos2 = oldRegion.getMaximumPoint().toBlockVector(); + + Vector center = pos1.add(pos2).divide(2).floor(); + region.setCenter(center); + region.setRadius(pos2.subtract(center)); + } + } + + public EllipsoidRegionSelector(LocalWorld world, Vector center, Vector radius) { + this(world); + + region.setCenter(center); + region.setRadius(radius); + } + + public boolean selectPrimary(Vector pos) { + if (pos.equals(region.getCenter()) && region.getRadius().lengthSq() == 0) { + return false; + } + + region.setCenter(pos.toBlockVector()); + region.setRadius(new Vector()); + return true; + } + + public boolean selectSecondary(Vector pos) { + final Vector diff = pos.subtract(region.getCenter()); + final Vector minRadius = Vector.getMaximum(diff, diff.multiply(-1.0)); + region.extendRadius(minRadius); + return true; + } + + public void explainPrimarySelection(LocalPlayer player, LocalSession session, Vector pos) { + if (isDefined()) { + player.print("Center position set to " + region.getCenter() + " (" + region.getArea() + ")."); + } else { + player.print("Center position set to " + region.getCenter() + "."); + } + + session.describeCUI(player); + } + + public void explainSecondarySelection(LocalPlayer player, LocalSession session, Vector pos) { + if (isDefined()) { + player.print("Radius set to " + region.getRadius() + " (" + region.getArea() + ")."); + } else { + player.print("Radius set to " + region.getRadius() + "."); + } + + session.describeCUI(player); + } + + public void explainRegionAdjust(LocalPlayer player, LocalSession session) { + session.describeCUI(player); + } + + public boolean isDefined() { + return region.getRadius().lengthSq() > 0; + } + + public EllipsoidRegion getRegion() throws IncompleteRegionException { + if (!isDefined()) { + throw new IncompleteRegionException(); + } + + return region; + } + + public EllipsoidRegion getIncompleteRegion() { + return region; + } + + public void learnChanges() { + } + + public void clear() { + region.setCenter(new Vector()); + region.setRadius(new Vector()); + } + + public String getTypeName() { + return "ellipsoid"; + } + + public List getInformationLines() { + final List lines = new ArrayList(); + + final Vector center = region.getCenter(); + if (center.lengthSq() > 0) { + lines.add("Center: " + center); + } + + final Vector radius = region.getRadius(); + if (radius.lengthSq() > 0) { + lines.add("X/Y/Z radius: " + radius); + } + + return lines; + } + + public int getArea() { + return region.getArea(); + } + + public void describeCUI(LocalSession session, LocalPlayer player) { + session.dispatchCUIEvent(player, new SelectionEllipsoidPointEvent(0, region.getCenter())); + session.dispatchCUIEvent(player, new SelectionEllipsoidPointEvent(1, region.getRadius())); + } + + public void describeLegacyCUI(LocalSession session, LocalPlayer player) { + session.dispatchCUIEvent(player, new SelectionPointEvent(0, region.getMinimumPoint(), getArea())); + session.dispatchCUIEvent(player, new SelectionPointEvent(1, region.getMaximumPoint(), getArea())); + } + + public String getLegacyTypeID() { + return "cuboid"; + } + + public int getProtocolVersion() { + return 1; + } + + public String getTypeID() { + return "ellipsoid"; + } + + @Override + public BlockVector getPrimaryPosition() throws IncompleteRegionException { + return region.getCenter().toBlockVector(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/regions/ExtendingCuboidRegionSelector.java b/src/main/java/com/sk89q/worldedit/regions/selector/ExtendingCuboidRegionSelector.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/regions/ExtendingCuboidRegionSelector.java rename to src/main/java/com/sk89q/worldedit/regions/selector/ExtendingCuboidRegionSelector.java index 6b453760b..8c1993bf3 100644 --- a/src/main/java/com/sk89q/worldedit/regions/ExtendingCuboidRegionSelector.java +++ b/src/main/java/com/sk89q/worldedit/regions/selector/ExtendingCuboidRegionSelector.java @@ -1,116 +1,116 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.BlockVector; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.LocalWorld; -import com.sk89q.worldedit.Vector; - -/** - * Alternative selector for cuboids. - * - * @author sk89q - */ -public class ExtendingCuboidRegionSelector extends CuboidRegionSelector { - public ExtendingCuboidRegionSelector(LocalWorld world) { - super(world); - } - - public ExtendingCuboidRegionSelector(RegionSelector oldSelector) { - super(oldSelector); - - if (pos1 == null || pos2 == null) { - return; - } - - pos1 = region.getMinimumPoint().toBlockVector(); - pos2 = region.getMaximumPoint().toBlockVector(); - region.setPos1(pos1); - region.setPos2(pos2); - } - - public ExtendingCuboidRegionSelector(LocalWorld world, Vector pos1, Vector pos2) { - this(world); - pos1 = Vector.getMinimum(pos1, pos2); - pos2 = Vector.getMaximum(pos1, pos2); - region.setPos1(pos1); - region.setPos2(pos2); - } - - @Override - public boolean selectPrimary(Vector pos) { - if (pos1 != null && pos2 != null && pos.compareTo(pos1) == 0 && pos.compareTo(pos2) == 0) { - return false; - } - - pos1 = pos2 = pos.toBlockVector(); - region.setPos1(pos1); - region.setPos2(pos2); - return true; - } - - @Override - public boolean selectSecondary(Vector pos) { - if (pos1 == null || pos2 == null) { - return selectPrimary(pos); - } - - if (region.contains(pos)) { - return false; - } - - double x1 = Math.min(pos.getX(), pos1.getX()); - double y1 = Math.min(pos.getY(), pos1.getY()); - double z1 = Math.min(pos.getZ(), pos1.getZ()); - - double x2 = Math.max(pos.getX(), pos2.getX()); - double y2 = Math.max(pos.getY(), pos2.getY()); - double z2 = Math.max(pos.getZ(), pos2.getZ()); - - final BlockVector o1 = pos1; - final BlockVector o2 = pos2; - pos1 = new BlockVector(x1, y1, z1); - pos2 = new BlockVector(x2, y2, z2); - region.setPos1(pos1); - region.setPos2(pos2); - - assert(region.contains(o1)); - assert(region.contains(o2)); - assert(region.contains(pos)); - - return true; - } - - @Override - public void explainPrimarySelection(LocalPlayer player, LocalSession session, Vector pos) { - player.print("Started selection at " + pos + " (" + region.getArea() + ")."); - - explainRegionAdjust(player, session); - } - - @Override - public void explainSecondarySelection(LocalPlayer player, LocalSession session, Vector pos) { - player.print("Extended selection to encompass " + pos + " (" + region.getArea() + ")."); - - explainRegionAdjust(player, session); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.selector; + +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.Vector; + +/** + * Alternative selector for cuboids. + * + * @author sk89q + */ +public class ExtendingCuboidRegionSelector extends CuboidRegionSelector { + public ExtendingCuboidRegionSelector(LocalWorld world) { + super(world); + } + + public ExtendingCuboidRegionSelector(RegionSelector oldSelector) { + super(oldSelector); + + if (pos1 == null || pos2 == null) { + return; + } + + pos1 = region.getMinimumPoint().toBlockVector(); + pos2 = region.getMaximumPoint().toBlockVector(); + region.setPos1(pos1); + region.setPos2(pos2); + } + + public ExtendingCuboidRegionSelector(LocalWorld world, Vector pos1, Vector pos2) { + this(world); + pos1 = Vector.getMinimum(pos1, pos2); + pos2 = Vector.getMaximum(pos1, pos2); + region.setPos1(pos1); + region.setPos2(pos2); + } + + @Override + public boolean selectPrimary(Vector pos) { + if (pos1 != null && pos2 != null && pos.compareTo(pos1) == 0 && pos.compareTo(pos2) == 0) { + return false; + } + + pos1 = pos2 = pos.toBlockVector(); + region.setPos1(pos1); + region.setPos2(pos2); + return true; + } + + @Override + public boolean selectSecondary(Vector pos) { + if (pos1 == null || pos2 == null) { + return selectPrimary(pos); + } + + if (region.contains(pos)) { + return false; + } + + double x1 = Math.min(pos.getX(), pos1.getX()); + double y1 = Math.min(pos.getY(), pos1.getY()); + double z1 = Math.min(pos.getZ(), pos1.getZ()); + + double x2 = Math.max(pos.getX(), pos2.getX()); + double y2 = Math.max(pos.getY(), pos2.getY()); + double z2 = Math.max(pos.getZ(), pos2.getZ()); + + final BlockVector o1 = pos1; + final BlockVector o2 = pos2; + pos1 = new BlockVector(x1, y1, z1); + pos2 = new BlockVector(x2, y2, z2); + region.setPos1(pos1); + region.setPos2(pos2); + + assert(region.contains(o1)); + assert(region.contains(o2)); + assert(region.contains(pos)); + + return true; + } + + @Override + public void explainPrimarySelection(LocalPlayer player, LocalSession session, Vector pos) { + player.print("Started selection at " + pos + " (" + region.getArea() + ")."); + + explainRegionAdjust(player, session); + } + + @Override + public void explainSecondarySelection(LocalPlayer player, LocalSession session, Vector pos) { + player.print("Extended selection to encompass " + pos + " (" + region.getArea() + ")."); + + explainRegionAdjust(player, session); + } +} diff --git a/src/main/java/com/sk89q/worldedit/regions/Polygonal2DRegionSelector.java b/src/main/java/com/sk89q/worldedit/regions/selector/Polygonal2DRegionSelector.java similarity index 93% rename from src/main/java/com/sk89q/worldedit/regions/Polygonal2DRegionSelector.java rename to src/main/java/com/sk89q/worldedit/regions/selector/Polygonal2DRegionSelector.java index 628179a96..9ad1896fa 100644 --- a/src/main/java/com/sk89q/worldedit/regions/Polygonal2DRegionSelector.java +++ b/src/main/java/com/sk89q/worldedit/regions/selector/Polygonal2DRegionSelector.java @@ -1,219 +1,221 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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 java.util.Collections; -import java.util.List; -import com.sk89q.worldedit.BlockVector; -import com.sk89q.worldedit.BlockVector2D; -import com.sk89q.worldedit.IncompleteRegionException; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.LocalWorld; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.cui.CUIRegion; -import com.sk89q.worldedit.cui.SelectionMinMaxEvent; -import com.sk89q.worldedit.cui.SelectionPoint2DEvent; -import com.sk89q.worldedit.cui.SelectionShapeEvent; - -/** - * Selector for polygonal regions. - * - * @author sk89q - */ -public class Polygonal2DRegionSelector implements RegionSelector, CUIRegion { - private int maxPoints; - private BlockVector pos1; - private Polygonal2DRegion region; - - @Deprecated - public Polygonal2DRegionSelector(LocalWorld world) { - this(world, 50); - } - - public Polygonal2DRegionSelector(LocalWorld world, int maxPoints) { - this.maxPoints = maxPoints; - region = new Polygonal2DRegion(world); - } - - @Deprecated - public Polygonal2DRegionSelector(RegionSelector oldSelector) { - this(oldSelector, 50); - } - - public Polygonal2DRegionSelector(RegionSelector oldSelector, int maxPoints) { - this(oldSelector.getIncompleteRegion().getWorld(), maxPoints); - if (oldSelector instanceof Polygonal2DRegionSelector) { - final Polygonal2DRegionSelector polygonal2DRegionSelector = (Polygonal2DRegionSelector) oldSelector; - - pos1 = polygonal2DRegionSelector.pos1; - region = new Polygonal2DRegion(polygonal2DRegionSelector.region); - } else { - final Region oldRegion; - try { - oldRegion = oldSelector.getRegion(); - } catch (IncompleteRegionException e) { - return; - } - - final int minY = oldRegion.getMinimumPoint().getBlockY(); - final int maxY = oldRegion.getMaximumPoint().getBlockY(); - - List points = oldRegion.polygonize(maxPoints); - - pos1 = points.get(0).toVector(minY).toBlockVector(); - region = new Polygonal2DRegion(oldRegion.getWorld(), points, minY, maxY); - } - } - - public Polygonal2DRegionSelector(LocalWorld world, List points, int minY, int maxY) { - final BlockVector2D pos2D = points.get(0); - pos1 = new BlockVector(pos2D.getX(), minY, pos2D.getZ()); - region = new Polygonal2DRegion(world, points, minY, maxY); - } - - public boolean selectPrimary(Vector pos) { - if (pos.equals(pos1)) { - return false; - } - - pos1 = pos.toBlockVector(); - region = new Polygonal2DRegion(region.getWorld()); - region.addPoint(pos); - region.expandY(pos.getBlockY()); - - return true; - } - - public boolean selectSecondary(Vector pos) { - if (region.size() > 0) { - final List points = region.getPoints(); - - final BlockVector2D lastPoint = points.get(region.size() - 1); - if (lastPoint.getBlockX() == pos.getBlockX() && lastPoint.getBlockZ() == pos.getBlockZ()) { - return false; - } - - if (maxPoints >= 0 && points.size() > maxPoints) { - return false; - } - } - - region.addPoint(pos); - region.expandY(pos.getBlockY()); - - return true; - } - - public void explainPrimarySelection(LocalPlayer player, LocalSession session, Vector pos) { - player.print("Starting a new polygon at " + pos + "."); - - session.dispatchCUIEvent(player, new SelectionShapeEvent(getTypeID())); - session.dispatchCUIEvent(player, new SelectionPoint2DEvent(0, pos, getArea())); - session.dispatchCUIEvent(player, new SelectionMinMaxEvent(region.getMinimumY(), region.getMaximumY())); - } - - public void explainSecondarySelection(LocalPlayer player, LocalSession session, Vector pos) { - player.print("Added point #" + region.size() + " at " + pos + "."); - - session.dispatchCUIEvent(player, new SelectionPoint2DEvent(region.size() - 1, pos, getArea())); - session.dispatchCUIEvent(player, new SelectionMinMaxEvent(region.getMinimumY(), region.getMaximumY())); - } - - public void explainRegionAdjust(LocalPlayer player, LocalSession session) { - session.dispatchCUIEvent(player, new SelectionShapeEvent(getTypeID())); - describeCUI(session, player); - } - - public BlockVector getPrimaryPosition() throws IncompleteRegionException { - if (pos1 == null) { - throw new IncompleteRegionException(); - } - - return pos1; - } - - public Polygonal2DRegion getRegion() throws IncompleteRegionException { - if (!isDefined()) { - throw new IncompleteRegionException(); - } - - return region; - } - - public Polygonal2DRegion getIncompleteRegion() { - return region; - } - - public boolean isDefined() { - return region.size() > 2; - } - - public void learnChanges() { - BlockVector2D pt = region.getPoints().get(0); - pos1 = new BlockVector(pt.getBlockX(), region.getMinimumPoint().getBlockY(), pt.getBlockZ()); - } - - public void clear() { - pos1 = null; - region = new Polygonal2DRegion(region.getWorld()); - } - - public String getTypeName() { - return "2Dx1D polygon"; - } - - public List getInformationLines() { - return Collections.singletonList("# points: " + region.size()); - } - - public int getArea() { - return region.getArea(); - } - - public int getPointCount() { - return region.getPoints().size(); - } - - public void describeCUI(LocalSession session, LocalPlayer player) { - final List points = region.getPoints(); - for (int id = 0; id < points.size(); id++) { - session.dispatchCUIEvent(player, new SelectionPoint2DEvent(id, points.get(id), getArea())); - } - - session.dispatchCUIEvent(player, new SelectionMinMaxEvent(region.getMinimumY(), region.getMaximumY())); - } - - public void describeLegacyCUI(LocalSession session, LocalPlayer player) { - describeCUI(session, player); - } - - public int getProtocolVersion() { - return 0; - } - - public String getTypeID() { - return "polygon2d"; - } - - public String getLegacyTypeID() { - return "polygon2d"; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.selector; + +import java.util.Collections; +import java.util.List; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.BlockVector2D; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.internal.cui.CUIRegion; +import com.sk89q.worldedit.internal.cui.SelectionMinMaxEvent; +import com.sk89q.worldedit.internal.cui.SelectionPoint2DEvent; +import com.sk89q.worldedit.internal.cui.SelectionShapeEvent; +import com.sk89q.worldedit.regions.Polygonal2DRegion; +import com.sk89q.worldedit.regions.Region; + +/** + * Selector for polygonal regions. + * + * @author sk89q + */ +public class Polygonal2DRegionSelector implements RegionSelector, CUIRegion { + private int maxPoints; + private BlockVector pos1; + private Polygonal2DRegion region; + + @Deprecated + public Polygonal2DRegionSelector(LocalWorld world) { + this(world, 50); + } + + public Polygonal2DRegionSelector(LocalWorld world, int maxPoints) { + this.maxPoints = maxPoints; + region = new Polygonal2DRegion(world); + } + + @Deprecated + public Polygonal2DRegionSelector(RegionSelector oldSelector) { + this(oldSelector, 50); + } + + public Polygonal2DRegionSelector(RegionSelector oldSelector, int maxPoints) { + this(oldSelector.getIncompleteRegion().getWorld(), maxPoints); + if (oldSelector instanceof Polygonal2DRegionSelector) { + final Polygonal2DRegionSelector polygonal2DRegionSelector = (Polygonal2DRegionSelector) oldSelector; + + pos1 = polygonal2DRegionSelector.pos1; + region = new Polygonal2DRegion(polygonal2DRegionSelector.region); + } else { + final Region oldRegion; + try { + oldRegion = oldSelector.getRegion(); + } catch (IncompleteRegionException e) { + return; + } + + final int minY = oldRegion.getMinimumPoint().getBlockY(); + final int maxY = oldRegion.getMaximumPoint().getBlockY(); + + List points = oldRegion.polygonize(maxPoints); + + pos1 = points.get(0).toVector(minY).toBlockVector(); + region = new Polygonal2DRegion(oldRegion.getWorld(), points, minY, maxY); + } + } + + public Polygonal2DRegionSelector(LocalWorld world, List points, int minY, int maxY) { + final BlockVector2D pos2D = points.get(0); + pos1 = new BlockVector(pos2D.getX(), minY, pos2D.getZ()); + region = new Polygonal2DRegion(world, points, minY, maxY); + } + + public boolean selectPrimary(Vector pos) { + if (pos.equals(pos1)) { + return false; + } + + pos1 = pos.toBlockVector(); + region = new Polygonal2DRegion(region.getWorld()); + region.addPoint(pos); + region.expandY(pos.getBlockY()); + + return true; + } + + public boolean selectSecondary(Vector pos) { + if (region.size() > 0) { + final List points = region.getPoints(); + + final BlockVector2D lastPoint = points.get(region.size() - 1); + if (lastPoint.getBlockX() == pos.getBlockX() && lastPoint.getBlockZ() == pos.getBlockZ()) { + return false; + } + + if (maxPoints >= 0 && points.size() > maxPoints) { + return false; + } + } + + region.addPoint(pos); + region.expandY(pos.getBlockY()); + + return true; + } + + public void explainPrimarySelection(LocalPlayer player, LocalSession session, Vector pos) { + player.print("Starting a new polygon at " + pos + "."); + + session.dispatchCUIEvent(player, new SelectionShapeEvent(getTypeID())); + session.dispatchCUIEvent(player, new SelectionPoint2DEvent(0, pos, getArea())); + session.dispatchCUIEvent(player, new SelectionMinMaxEvent(region.getMinimumY(), region.getMaximumY())); + } + + public void explainSecondarySelection(LocalPlayer player, LocalSession session, Vector pos) { + player.print("Added point #" + region.size() + " at " + pos + "."); + + session.dispatchCUIEvent(player, new SelectionPoint2DEvent(region.size() - 1, pos, getArea())); + session.dispatchCUIEvent(player, new SelectionMinMaxEvent(region.getMinimumY(), region.getMaximumY())); + } + + public void explainRegionAdjust(LocalPlayer player, LocalSession session) { + session.dispatchCUIEvent(player, new SelectionShapeEvent(getTypeID())); + describeCUI(session, player); + } + + public BlockVector getPrimaryPosition() throws IncompleteRegionException { + if (pos1 == null) { + throw new IncompleteRegionException(); + } + + return pos1; + } + + public Polygonal2DRegion getRegion() throws IncompleteRegionException { + if (!isDefined()) { + throw new IncompleteRegionException(); + } + + return region; + } + + public Polygonal2DRegion getIncompleteRegion() { + return region; + } + + public boolean isDefined() { + return region.size() > 2; + } + + public void learnChanges() { + BlockVector2D pt = region.getPoints().get(0); + pos1 = new BlockVector(pt.getBlockX(), region.getMinimumPoint().getBlockY(), pt.getBlockZ()); + } + + public void clear() { + pos1 = null; + region = new Polygonal2DRegion(region.getWorld()); + } + + public String getTypeName() { + return "2Dx1D polygon"; + } + + public List getInformationLines() { + return Collections.singletonList("# points: " + region.size()); + } + + public int getArea() { + return region.getArea(); + } + + public int getPointCount() { + return region.getPoints().size(); + } + + public void describeCUI(LocalSession session, LocalPlayer player) { + final List points = region.getPoints(); + for (int id = 0; id < points.size(); id++) { + session.dispatchCUIEvent(player, new SelectionPoint2DEvent(id, points.get(id), getArea())); + } + + session.dispatchCUIEvent(player, new SelectionMinMaxEvent(region.getMinimumY(), region.getMaximumY())); + } + + public void describeLegacyCUI(LocalSession session, LocalPlayer player) { + describeCUI(session, player); + } + + public int getProtocolVersion() { + return 0; + } + + public String getTypeID() { + return "polygon2d"; + } + + public String getLegacyTypeID() { + return "polygon2d"; + } +} diff --git a/src/main/java/com/sk89q/worldedit/regions/RegionSelector.java b/src/main/java/com/sk89q/worldedit/regions/selector/RegionSelector.java similarity index 89% rename from src/main/java/com/sk89q/worldedit/regions/RegionSelector.java rename to src/main/java/com/sk89q/worldedit/regions/selector/RegionSelector.java index e27ee48ef..243657a64 100644 --- a/src/main/java/com/sk89q/worldedit/regions/RegionSelector.java +++ b/src/main/java/com/sk89q/worldedit/regions/selector/RegionSelector.java @@ -1,140 +1,138 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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 java.util.List; -import com.sk89q.worldedit.BlockVector; -import com.sk89q.worldedit.IncompleteRegionException; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.Vector; - -/** - * Region selection factory. - * - * @author sk89q - */ -public interface RegionSelector { - /** - * Called when the first point is selected. - * - * @param pos - * @return true if something changed - */ - public boolean selectPrimary(Vector pos); - - /** - * Called when the second point is selected. - * - * @param pos - * @return true if something changed - */ - public boolean selectSecondary(Vector pos); - - /** - * Tell the player information about his/her primary selection. - * - * @param player - * @param session - * @param pos - */ - public void explainPrimarySelection(LocalPlayer player, - LocalSession session, Vector pos); - - /** - * Tell the player information about his/her secondary selection. - * - * @param player - * @param session - * @param pos - */ - public void explainSecondarySelection(LocalPlayer player, - LocalSession session, Vector pos); - - /** - * The the player information about the region's changes. This may resend - * all the defining region information if needed. - * - * @param player - * @param session - */ - public void explainRegionAdjust(LocalPlayer player, LocalSession session); - - /** - * Get the primary position. - * - * @return - * @throws IncompleteRegionException - */ - public BlockVector getPrimaryPosition() throws IncompleteRegionException; - - /** - * Get the selection. - * - * @return - * @throws IncompleteRegionException - */ - public Region getRegion() throws IncompleteRegionException; - - /** - * Get the region even if it's not fully defined. - * - * @return - */ - public Region getIncompleteRegion(); - - /** - * Returns whether the region has been fully defined. - * - * @return - */ - public boolean isDefined(); - - /** - * Get the number of blocks inside the region. - * - * @return number of blocks or -1 if undefined - */ - public int getArea(); - - /** - * Update the selector with changes to the region. - */ - public void learnChanges(); - - /** - * Clear the selection. - */ - public void clear(); - - /** - * Get a lowercase name of this region selector type. - * - * @return - */ - public String getTypeName(); - - /** - * Get lines of information about the selection. - * - * @return - */ - public List getInformationLines(); -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.selector; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.regions.Region; + +import java.util.List; + +/** + * Region selection factory. + * + * @author sk89q + */ +public interface RegionSelector { + /** + * Called when the first point is selected. + * + * @param pos + * @return true if something changed + */ + public boolean selectPrimary(Vector pos); + + /** + * Called when the second point is selected. + * + * @param pos + * @return true if something changed + */ + public boolean selectSecondary(Vector pos); + + /** + * Tell the player information about his/her primary selection. + * + * @param player + * @param session + * @param pos + */ + public void explainPrimarySelection(LocalPlayer player, + LocalSession session, Vector pos); + + /** + * Tell the player information about his/her secondary selection. + * + * @param player + * @param session + * @param pos + */ + public void explainSecondarySelection(LocalPlayer player, + LocalSession session, Vector pos); + + /** + * The the player information about the region's changes. This may resend + * all the defining region information if needed. + * + * @param player + * @param session + */ + public void explainRegionAdjust(LocalPlayer player, LocalSession session); + + /** + * Get the primary position. + * + * @return + * @throws IncompleteRegionException + */ + public BlockVector getPrimaryPosition() throws IncompleteRegionException; + + /** + * Get the selection. + * + * @return + * @throws IncompleteRegionException + */ + public Region getRegion() throws IncompleteRegionException; + + /** + * Get the region even if it's not fully defined. + * + * @return + */ + public Region getIncompleteRegion(); + + /** + * Returns whether the region has been fully defined. + * + * @return + */ + public boolean isDefined(); + + /** + * Get the number of blocks inside the region. + * + * @return number of blocks or -1 if undefined + */ + public int getArea(); + + /** + * Update the selector with changes to the region. + */ + public void learnChanges(); + + /** + * Clear the selection. + */ + public void clear(); + + /** + * Get a lowercase name of this region selector type. + * + * @return + */ + public String getTypeName(); + + /** + * Get lines of information about the selection. + * + * @return + */ + public List getInformationLines(); +} diff --git a/src/main/java/com/sk89q/worldedit/regions/SphereRegionSelector.java b/src/main/java/com/sk89q/worldedit/regions/selector/SphereRegionSelector.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/regions/SphereRegionSelector.java rename to src/main/java/com/sk89q/worldedit/regions/selector/SphereRegionSelector.java index 6281205ca..22da10935 100644 --- a/src/main/java/com/sk89q/worldedit/regions/SphereRegionSelector.java +++ b/src/main/java/com/sk89q/worldedit/regions/selector/SphereRegionSelector.java @@ -1,75 +1,75 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.LocalPlayer; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.LocalWorld; -import com.sk89q.worldedit.Vector; - -/** - * Selector for spheres. - * - * @author TomyLobo - */ -public class SphereRegionSelector extends EllipsoidRegionSelector { - public SphereRegionSelector(LocalWorld world) { - super(world); - } - - public SphereRegionSelector() { - super(); - } - - public SphereRegionSelector(RegionSelector oldSelector) { - super(oldSelector); - final Vector radius = region.getRadius(); - final double radiusScalar = Math.max(Math.max(radius.getX(), radius.getY()), radius.getZ()); - region.setRadius(new Vector(radiusScalar, radiusScalar, radiusScalar)); - } - - public SphereRegionSelector(LocalWorld world, Vector center, int radius) { - super(world, center, new Vector(radius, radius, radius)); - } - - @Override - public boolean selectSecondary(Vector pos) { - final double radiusScalar = Math.ceil(pos.distance(region.getCenter())); - region.setRadius(new Vector(radiusScalar, radiusScalar, radiusScalar)); - - return true; - } - - @Override - public void explainSecondarySelection(LocalPlayer player, LocalSession session, Vector pos) { - if (isDefined()) { - player.print("Radius set to " + region.getRadius().getX() + " (" + region.getArea() + ")."); - } else { - player.print("Radius set to " + region.getRadius().getX() + "."); - } - - session.describeCUI(player); - } - - @Override - public String getTypeName() { - return "sphere"; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.selector; + +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.Vector; + +/** + * Selector for spheres. + * + * @author TomyLobo + */ +public class SphereRegionSelector extends EllipsoidRegionSelector { + public SphereRegionSelector(LocalWorld world) { + super(world); + } + + public SphereRegionSelector() { + super(); + } + + public SphereRegionSelector(RegionSelector oldSelector) { + super(oldSelector); + final Vector radius = region.getRadius(); + final double radiusScalar = Math.max(Math.max(radius.getX(), radius.getY()), radius.getZ()); + region.setRadius(new Vector(radiusScalar, radiusScalar, radiusScalar)); + } + + public SphereRegionSelector(LocalWorld world, Vector center, int radius) { + super(world, center, new Vector(radius, radius, radius)); + } + + @Override + public boolean selectSecondary(Vector pos) { + final double radiusScalar = Math.ceil(pos.distance(region.getCenter())); + region.setRadius(new Vector(radiusScalar, radiusScalar, radiusScalar)); + + return true; + } + + @Override + public void explainSecondarySelection(LocalPlayer player, LocalSession session, Vector pos) { + if (isDefined()) { + player.print("Radius set to " + region.getRadius().getX() + " (" + region.getArea() + ")."); + } else { + player.print("Radius set to " + region.getRadius().getX() + "."); + } + + session.describeCUI(player); + } + + @Override + public String getTypeName() { + return "sphere"; + } +} diff --git a/src/main/java/com/sk89q/worldedit/shape/ArbitraryBiomeShape.java b/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryBiomeShape.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/shape/ArbitraryBiomeShape.java rename to src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryBiomeShape.java index 9b2c3c273..81130e22e 100644 --- a/src/main/java/com/sk89q/worldedit/shape/ArbitraryBiomeShape.java +++ b/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryBiomeShape.java @@ -1,189 +1,189 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.shape; - -import com.sk89q.worldedit.BiomeType; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.Vector2D; -import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.regions.FlatRegion; -import com.sk89q.worldedit.regions.Region; - -/** - * Generates solid and hollow shapes according to materials returned by the - * {@link #getBiome} method. - * - * @author TomyLobo - */ -public abstract class ArbitraryBiomeShape { - private final FlatRegion extent; - private int cacheOffsetX; - private int cacheOffsetZ; - @SuppressWarnings("FieldCanBeLocal") - private int cacheSizeX; - private int cacheSizeZ; - - public ArbitraryBiomeShape(Region extent) { - if (extent instanceof FlatRegion) { - this.extent = (FlatRegion) extent; - } - else { - // TODO: polygonize - this.extent = new CuboidRegion(extent.getWorld(), extent.getMinimumPoint(), extent.getMaximumPoint()); - } - - Vector2D min = extent.getMinimumPoint().toVector2D(); - Vector2D max = extent.getMaximumPoint().toVector2D(); - - cacheOffsetX = min.getBlockX() - 1; - cacheOffsetZ = min.getBlockZ() - 1; - - cacheSizeX = (int) (max.getX() - cacheOffsetX + 2); - cacheSizeZ = (int) (max.getZ() - cacheOffsetZ + 2); - - cache = new BiomeType[cacheSizeX * cacheSizeZ]; - } - - protected Iterable getExtent() { - return extent.asFlatRegion(); - } - - - /** - * Cache entries: - * null = unknown - * OUTSIDE = outside - * else = inside - */ - private final BiomeType[] cache; - - /** - * Override this function to specify the shape to generate. - * - * @param x X coordinate to be queried - * @param z Z coordinate to be queried - * @param defaultBiomeType The default biome for the current column. - * @return material to place or null to not place anything. - */ - protected abstract BiomeType getBiome(int x, int z, BiomeType defaultBiomeType); - - private BiomeType getBiomeCached(int x, int z, BiomeType biomeType) { - final int index = (z - cacheOffsetZ) + (x - cacheOffsetX) * cacheSizeZ; - - final BiomeType cacheEntry = cache[index]; - if (cacheEntry == null) {// unknown, fetch material - final BiomeType material = getBiome(x, z, biomeType); - if (material == null) { - // outside - cache[index] = OUTSIDE; - return null; - } - - cache[index] = material; - return material; - } - - if (cacheEntry == OUTSIDE) { - // outside - return null; - } - - return cacheEntry; - } - - private boolean isInsideCached(int x, int z, BiomeType biomeType) { - final int index = (z - cacheOffsetZ) + (x - cacheOffsetX) * cacheSizeZ; - - final BiomeType cacheEntry = cache[index]; - if (cacheEntry == null) { - // unknown block, meaning they must be outside the extent at this stage, but might still be inside the shape - return getBiomeCached(x, z, biomeType) != null; - } - - return cacheEntry != OUTSIDE; - } - - /** - * Generates the shape. - * - * @param editSession The EditSession to use. - * @param biomeType The default biome type. - * @param hollow Specifies whether to generate a hollow shape. - * @return number of affected blocks. - */ - public int generate(EditSession editSession, BiomeType biomeType, boolean hollow) { - int affected = 0; - - for (Vector2D position : getExtent()) { - int x = position.getBlockX(); - int z = position.getBlockZ(); - - if (!hollow) { - final BiomeType material = getBiome(x, z, biomeType); - if (material != OUTSIDE) { - editSession.getWorld().setBiome(position, material); - ++affected; - } - - continue; - } - - final BiomeType material = getBiomeCached(x, z, biomeType); - if (material == null) { - continue; - } - - boolean draw = false; - do { - if (!isInsideCached(x + 1, z, biomeType)) { - draw = true; - break; - } - if (!isInsideCached(x - 1, z, biomeType)) { - draw = true; - break; - } - if (!isInsideCached(x, z + 1, biomeType)) { - draw = true; - break; - } - if (!isInsideCached(x, z - 1, biomeType)) { - draw = true; - break; - } - } while (false); - - if (!draw) { - continue; - } - - editSession.getWorld().setBiome(position, material); - ++affected; - } - - return affected; - } - - private static final BiomeType OUTSIDE = new BiomeType() { - public String getName() { - throw new UnsupportedOperationException(); - } - }; -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.shape; + +import com.sk89q.worldedit.BiomeType; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.FlatRegion; +import com.sk89q.worldedit.regions.Region; + +/** + * Generates solid and hollow shapes according to materials returned by the + * {@link #getBiome} method. + * + * @author TomyLobo + */ +public abstract class ArbitraryBiomeShape { + private final FlatRegion extent; + private int cacheOffsetX; + private int cacheOffsetZ; + @SuppressWarnings("FieldCanBeLocal") + private int cacheSizeX; + private int cacheSizeZ; + + public ArbitraryBiomeShape(Region extent) { + if (extent instanceof FlatRegion) { + this.extent = (FlatRegion) extent; + } + else { + // TODO: polygonize + this.extent = new CuboidRegion(extent.getWorld(), extent.getMinimumPoint(), extent.getMaximumPoint()); + } + + Vector2D min = extent.getMinimumPoint().toVector2D(); + Vector2D max = extent.getMaximumPoint().toVector2D(); + + cacheOffsetX = min.getBlockX() - 1; + cacheOffsetZ = min.getBlockZ() - 1; + + cacheSizeX = (int) (max.getX() - cacheOffsetX + 2); + cacheSizeZ = (int) (max.getZ() - cacheOffsetZ + 2); + + cache = new BiomeType[cacheSizeX * cacheSizeZ]; + } + + protected Iterable getExtent() { + return extent.asFlatRegion(); + } + + + /** + * Cache entries: + * null = unknown + * OUTSIDE = outside + * else = inside + */ + private final BiomeType[] cache; + + /** + * Override this function to specify the shape to generate. + * + * @param x X coordinate to be queried + * @param z Z coordinate to be queried + * @param defaultBiomeType The default biome for the current column. + * @return material to place or null to not place anything. + */ + protected abstract BiomeType getBiome(int x, int z, BiomeType defaultBiomeType); + + private BiomeType getBiomeCached(int x, int z, BiomeType biomeType) { + final int index = (z - cacheOffsetZ) + (x - cacheOffsetX) * cacheSizeZ; + + final BiomeType cacheEntry = cache[index]; + if (cacheEntry == null) {// unknown, fetch material + final BiomeType material = getBiome(x, z, biomeType); + if (material == null) { + // outside + cache[index] = OUTSIDE; + return null; + } + + cache[index] = material; + return material; + } + + if (cacheEntry == OUTSIDE) { + // outside + return null; + } + + return cacheEntry; + } + + private boolean isInsideCached(int x, int z, BiomeType biomeType) { + final int index = (z - cacheOffsetZ) + (x - cacheOffsetX) * cacheSizeZ; + + final BiomeType cacheEntry = cache[index]; + if (cacheEntry == null) { + // unknown block, meaning they must be outside the extent at this stage, but might still be inside the shape + return getBiomeCached(x, z, biomeType) != null; + } + + return cacheEntry != OUTSIDE; + } + + /** + * Generates the shape. + * + * @param editSession The EditSession to use. + * @param biomeType The default biome type. + * @param hollow Specifies whether to generate a hollow shape. + * @return number of affected blocks. + */ + public int generate(EditSession editSession, BiomeType biomeType, boolean hollow) { + int affected = 0; + + for (Vector2D position : getExtent()) { + int x = position.getBlockX(); + int z = position.getBlockZ(); + + if (!hollow) { + final BiomeType material = getBiome(x, z, biomeType); + if (material != OUTSIDE) { + editSession.getWorld().setBiome(position, material); + ++affected; + } + + continue; + } + + final BiomeType material = getBiomeCached(x, z, biomeType); + if (material == null) { + continue; + } + + boolean draw = false; + do { + if (!isInsideCached(x + 1, z, biomeType)) { + draw = true; + break; + } + if (!isInsideCached(x - 1, z, biomeType)) { + draw = true; + break; + } + if (!isInsideCached(x, z + 1, biomeType)) { + draw = true; + break; + } + if (!isInsideCached(x, z - 1, biomeType)) { + draw = true; + break; + } + } while (false); + + if (!draw) { + continue; + } + + editSession.getWorld().setBiome(position, material); + ++affected; + } + + return affected; + } + + private static final BiomeType OUTSIDE = new BiomeType() { + public String getName() { + throw new UnsupportedOperationException(); + } + }; +} diff --git a/src/main/java/com/sk89q/worldedit/shape/ArbitraryShape.java b/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryShape.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/shape/ArbitraryShape.java rename to src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryShape.java index 785a10013..589a85301 100644 --- a/src/main/java/com/sk89q/worldedit/shape/ArbitraryShape.java +++ b/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryShape.java @@ -1,211 +1,211 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.shape; - -import com.sk89q.worldedit.BlockVector; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.patterns.Pattern; -import com.sk89q.worldedit.regions.Region; - -/** - * Generates solid and hollow shapes according to materials returned by the - * {@link #getMaterial} method. - * - * @author TomyLobo - */ -public abstract class ArbitraryShape { - protected final Region extent; - private int cacheOffsetX; - private int cacheOffsetY; - private int cacheOffsetZ; - @SuppressWarnings("FieldCanBeLocal") - private int cacheSizeX; - private int cacheSizeY; - private int cacheSizeZ; - - public ArbitraryShape(Region extent) { - this.extent = extent; - - Vector min = extent.getMinimumPoint(); - Vector max = extent.getMaximumPoint(); - - cacheOffsetX = min.getBlockX() - 1; - cacheOffsetY = min.getBlockY() - 1; - cacheOffsetZ = min.getBlockZ() - 1; - - cacheSizeX = (int) (max.getX() - cacheOffsetX + 2); - cacheSizeY = (int) (max.getY() - cacheOffsetY + 2); - cacheSizeZ = (int) (max.getZ() - cacheOffsetZ + 2); - - cache = new short[cacheSizeX * cacheSizeY * cacheSizeZ]; - } - - protected Region getExtent() { - return extent; - } - - - /** - * Cache entries: - * 0 = unknown - * -1 = outside - * -2 = inside but type and data 0 - * > 0 = inside, value = (type | (data << 8)), not handling data < 0 - */ - private final short[] cache; - - /** - * Override this function to specify the shape to generate. - * - * @param x X coordinate to be queried - * @param y Y coordinate to be queried - * @param z Z coordinate to be queried - * @param defaultMaterial The material returned by the pattern for the current block. - * @return material to place or null to not place anything. - */ - protected abstract BaseBlock getMaterial(int x, int y, int z, BaseBlock defaultMaterial); - - private BaseBlock getMaterialCached(int x, int y, int z, Pattern pattern) { - final int index = (y - cacheOffsetY) + (z - cacheOffsetZ) * cacheSizeY + (x - cacheOffsetX) * cacheSizeY * cacheSizeZ; - - final short cacheEntry = cache[index]; - switch (cacheEntry) { - case 0: - // unknown, fetch material - final BaseBlock material = getMaterial(x, y, z, pattern.next(new BlockVector(x, y, z))); - if (material == null) { - // outside - cache[index] = -1; - return null; - } - - short newCacheEntry = (short) (material.getType() | ((material.getData() + 1) << 8)); - if (newCacheEntry == 0) { - // type and data 0 - newCacheEntry = -2; - } - - cache[index] = newCacheEntry; - return material; - - case -1: - // outside - return null; - - case -2: - // type and data 0 - return new BaseBlock(0, 0); - } - - return new BaseBlock(cacheEntry & 255, ((cacheEntry >> 8) - 1) & 15); - } - - private boolean isInsideCached(int x, int y, int z, Pattern pattern) { - final int index = (y - cacheOffsetY) + (z - cacheOffsetZ) * cacheSizeY + (x - cacheOffsetX) * cacheSizeY * cacheSizeZ; - - switch (cache[index]) { - case 0: - // unknown block, meaning they must be outside the extent at this stage, but might still be inside the shape - return getMaterialCached(x, y, z, pattern) != null; - - case -1: - // outside - return false; - - default: - // inside - return true; - } - } - - /** - * Generates the shape. - * - * @param editSession The EditSession to use. - * @param pattern The pattern to generate default materials from. - * @param hollow Specifies whether to generate a hollow shape. - * @return number of affected blocks. - * @throws MaxChangedBlocksException - */ - public int generate(EditSession editSession, Pattern pattern, boolean hollow) throws MaxChangedBlocksException { - int affected = 0; - - for (BlockVector position : getExtent()) { - int x = position.getBlockX(); - int y = position.getBlockY(); - int z = position.getBlockZ(); - - if (!hollow) { - final BaseBlock material = getMaterial(x, y, z, pattern.next(position)); - if (material != null && editSession.setBlock(position, material)) { - ++affected; - } - - continue; - } - - final BaseBlock material = getMaterialCached(x, y, z, pattern); - if (material == null) { - continue; - } - - boolean draw = false; - do { - if (!isInsideCached(x + 1, y, z, pattern)) { - draw = true; - break; - } - if (!isInsideCached(x - 1, y, z, pattern)) { - draw = true; - break; - } - if (!isInsideCached(x, y, z + 1, pattern)) { - draw = true; - break; - } - if (!isInsideCached(x, y, z - 1, pattern)) { - draw = true; - break; - } - if (!isInsideCached(x, y + 1, z, pattern)) { - draw = true; - break; - } - if (!isInsideCached(x, y - 1, z, pattern)) { - draw = true; - break; - } - } while (false); - - if (!draw) { - continue; - } - - if (editSession.setBlock(position, material)) { - ++affected; - } - } - - return affected; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.shape; + +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.patterns.Pattern; +import com.sk89q.worldedit.regions.Region; + +/** + * Generates solid and hollow shapes according to materials returned by the + * {@link #getMaterial} method. + * + * @author TomyLobo + */ +public abstract class ArbitraryShape { + protected final Region extent; + private int cacheOffsetX; + private int cacheOffsetY; + private int cacheOffsetZ; + @SuppressWarnings("FieldCanBeLocal") + private int cacheSizeX; + private int cacheSizeY; + private int cacheSizeZ; + + public ArbitraryShape(Region extent) { + this.extent = extent; + + Vector min = extent.getMinimumPoint(); + Vector max = extent.getMaximumPoint(); + + cacheOffsetX = min.getBlockX() - 1; + cacheOffsetY = min.getBlockY() - 1; + cacheOffsetZ = min.getBlockZ() - 1; + + cacheSizeX = (int) (max.getX() - cacheOffsetX + 2); + cacheSizeY = (int) (max.getY() - cacheOffsetY + 2); + cacheSizeZ = (int) (max.getZ() - cacheOffsetZ + 2); + + cache = new short[cacheSizeX * cacheSizeY * cacheSizeZ]; + } + + protected Region getExtent() { + return extent; + } + + + /** + * Cache entries: + * 0 = unknown + * -1 = outside + * -2 = inside but type and data 0 + * > 0 = inside, value = (type | (data << 8)), not handling data < 0 + */ + private final short[] cache; + + /** + * Override this function to specify the shape to generate. + * + * @param x X coordinate to be queried + * @param y Y coordinate to be queried + * @param z Z coordinate to be queried + * @param defaultMaterial The material returned by the pattern for the current block. + * @return material to place or null to not place anything. + */ + protected abstract BaseBlock getMaterial(int x, int y, int z, BaseBlock defaultMaterial); + + private BaseBlock getMaterialCached(int x, int y, int z, Pattern pattern) { + final int index = (y - cacheOffsetY) + (z - cacheOffsetZ) * cacheSizeY + (x - cacheOffsetX) * cacheSizeY * cacheSizeZ; + + final short cacheEntry = cache[index]; + switch (cacheEntry) { + case 0: + // unknown, fetch material + final BaseBlock material = getMaterial(x, y, z, pattern.next(new BlockVector(x, y, z))); + if (material == null) { + // outside + cache[index] = -1; + return null; + } + + short newCacheEntry = (short) (material.getType() | ((material.getData() + 1) << 8)); + if (newCacheEntry == 0) { + // type and data 0 + newCacheEntry = -2; + } + + cache[index] = newCacheEntry; + return material; + + case -1: + // outside + return null; + + case -2: + // type and data 0 + return new BaseBlock(0, 0); + } + + return new BaseBlock(cacheEntry & 255, ((cacheEntry >> 8) - 1) & 15); + } + + private boolean isInsideCached(int x, int y, int z, Pattern pattern) { + final int index = (y - cacheOffsetY) + (z - cacheOffsetZ) * cacheSizeY + (x - cacheOffsetX) * cacheSizeY * cacheSizeZ; + + switch (cache[index]) { + case 0: + // unknown block, meaning they must be outside the extent at this stage, but might still be inside the shape + return getMaterialCached(x, y, z, pattern) != null; + + case -1: + // outside + return false; + + default: + // inside + return true; + } + } + + /** + * Generates the shape. + * + * @param editSession The EditSession to use. + * @param pattern The pattern to generate default materials from. + * @param hollow Specifies whether to generate a hollow shape. + * @return number of affected blocks. + * @throws MaxChangedBlocksException + */ + public int generate(EditSession editSession, Pattern pattern, boolean hollow) throws MaxChangedBlocksException { + int affected = 0; + + for (BlockVector position : getExtent()) { + int x = position.getBlockX(); + int y = position.getBlockY(); + int z = position.getBlockZ(); + + if (!hollow) { + final BaseBlock material = getMaterial(x, y, z, pattern.next(position)); + if (material != null && editSession.setBlock(position, material)) { + ++affected; + } + + continue; + } + + final BaseBlock material = getMaterialCached(x, y, z, pattern); + if (material == null) { + continue; + } + + boolean draw = false; + do { + if (!isInsideCached(x + 1, y, z, pattern)) { + draw = true; + break; + } + if (!isInsideCached(x - 1, y, z, pattern)) { + draw = true; + break; + } + if (!isInsideCached(x, y, z + 1, pattern)) { + draw = true; + break; + } + if (!isInsideCached(x, y, z - 1, pattern)) { + draw = true; + break; + } + if (!isInsideCached(x, y + 1, z, pattern)) { + draw = true; + break; + } + if (!isInsideCached(x, y - 1, z, pattern)) { + draw = true; + break; + } + } while (false); + + if (!draw) { + continue; + } + + if (editSession.setBlock(position, material)) { + ++affected; + } + } + + return affected; + } +} diff --git a/src/main/java/com/sk89q/worldedit/shape/RegionShape.java b/src/main/java/com/sk89q/worldedit/regions/shape/RegionShape.java similarity index 84% rename from src/main/java/com/sk89q/worldedit/shape/RegionShape.java rename to src/main/java/com/sk89q/worldedit/regions/shape/RegionShape.java index 74cafe2b8..caab57190 100644 --- a/src/main/java/com/sk89q/worldedit/shape/RegionShape.java +++ b/src/main/java/com/sk89q/worldedit/regions/shape/RegionShape.java @@ -1,27 +1,26 @@ -package com.sk89q.worldedit.shape; - -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.shape.ArbitraryShape; - -/** - * Generates solid and hollow shapes according to materials returned by the - * {@link #getMaterial} method. - * - * @author TomyLobo - */ -public class RegionShape extends ArbitraryShape { - public RegionShape(Region extent) { - super(extent); - } - - @Override - protected BaseBlock getMaterial(int x, int y, int z, BaseBlock defaultMaterial) { - if (!this.extent.contains(new Vector(x, y, z))) { - return null; - } - - return defaultMaterial; - } -} +package com.sk89q.worldedit.regions.shape; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.regions.Region; + +/** + * Generates solid and hollow shapes according to materials returned by the + * {@link #getMaterial} method. + * + * @author TomyLobo + */ +public class RegionShape extends ArbitraryShape { + public RegionShape(Region extent) { + super(extent); + } + + @Override + protected BaseBlock getMaterial(int x, int y, int z, BaseBlock defaultMaterial) { + if (!this.extent.contains(new Vector(x, y, z))) { + return null; + } + + return defaultMaterial; + } +} diff --git a/src/main/java/com/sk89q/worldedit/shape/WorldEditExpressionEnvironment.java b/src/main/java/com/sk89q/worldedit/regions/shape/WorldEditExpressionEnvironment.java similarity index 91% rename from src/main/java/com/sk89q/worldedit/shape/WorldEditExpressionEnvironment.java rename to src/main/java/com/sk89q/worldedit/regions/shape/WorldEditExpressionEnvironment.java index f026bc5f4..a81dead3f 100644 --- a/src/main/java/com/sk89q/worldedit/shape/WorldEditExpressionEnvironment.java +++ b/src/main/java/com/sk89q/worldedit/regions/shape/WorldEditExpressionEnvironment.java @@ -1,62 +1,62 @@ -package com.sk89q.worldedit.shape; - -import com.sk89q.worldedit.BlockVector; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.expression.runtime.ExpressionEnvironment; - -public class WorldEditExpressionEnvironment implements ExpressionEnvironment { - private final Vector unit; - private final Vector zero2; - private Vector current = new Vector(); - private EditSession editSession; - - public WorldEditExpressionEnvironment(EditSession editSession, Vector unit, Vector zero) { - this.editSession = editSession; - this.unit = unit; - this.zero2 = zero.add(0.5, 0.5, 0.5); - } - - public BlockVector toWorld(double x, double y, double z) { - // unscale, unoffset, round-nearest - return new Vector(x, y, z).multiply(unit).add(zero2).toBlockPoint(); - } - - public Vector toWorldRel(double x, double y, double z) { - return current.add(x, y, z); - } - - @Override - public int getBlockType(double x, double y, double z) { - return editSession.getBlockType(toWorld(x, y, z)); - } - - @Override - public int getBlockData(double x, double y, double z) { - return editSession.getBlockData(toWorld(x, y, z)); - } - - @Override - public int getBlockTypeAbs(double x, double y, double z) { - return editSession.getBlockType(new Vector(x, y, z)); - } - - @Override - public int getBlockDataAbs(double x, double y, double z) { - return editSession.getBlockData(new Vector(x, y, z)); - } - - @Override - public int getBlockTypeRel(double x, double y, double z) { - return editSession.getBlockType(toWorldRel(x, y, z)); - } - - @Override - public int getBlockDataRel(double x, double y, double z) { - return editSession.getBlockData(toWorldRel(x, y, z)); - } - - public void setCurrentBlock(Vector current) { - this.current = current; - } -} +package com.sk89q.worldedit.regions.shape; + +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.internal.expression.runtime.ExpressionEnvironment; + +public class WorldEditExpressionEnvironment implements ExpressionEnvironment { + private final Vector unit; + private final Vector zero2; + private Vector current = new Vector(); + private EditSession editSession; + + public WorldEditExpressionEnvironment(EditSession editSession, Vector unit, Vector zero) { + this.editSession = editSession; + this.unit = unit; + this.zero2 = zero.add(0.5, 0.5, 0.5); + } + + public BlockVector toWorld(double x, double y, double z) { + // unscale, unoffset, round-nearest + return new Vector(x, y, z).multiply(unit).add(zero2).toBlockPoint(); + } + + public Vector toWorldRel(double x, double y, double z) { + return current.add(x, y, z); + } + + @Override + public int getBlockType(double x, double y, double z) { + return editSession.getBlockType(toWorld(x, y, z)); + } + + @Override + public int getBlockData(double x, double y, double z) { + return editSession.getBlockData(toWorld(x, y, z)); + } + + @Override + public int getBlockTypeAbs(double x, double y, double z) { + return editSession.getBlockType(new Vector(x, y, z)); + } + + @Override + public int getBlockDataAbs(double x, double y, double z) { + return editSession.getBlockData(new Vector(x, y, z)); + } + + @Override + public int getBlockTypeRel(double x, double y, double z) { + return editSession.getBlockType(toWorldRel(x, y, z)); + } + + @Override + public int getBlockDataRel(double x, double y, double z) { + return editSession.getBlockData(toWorldRel(x, y, z)); + } + + public void setCurrentBlock(Vector current) { + this.current = current; + } +} diff --git a/src/main/java/com/sk89q/worldedit/schematic/MCEditSchematicFormat.java b/src/main/java/com/sk89q/worldedit/schematic/MCEditSchematicFormat.java index d654bed5d..e6e5e1892 100644 --- a/src/main/java/com/sk89q/worldedit/schematic/MCEditSchematicFormat.java +++ b/src/main/java/com/sk89q/worldedit/schematic/MCEditSchematicFormat.java @@ -45,7 +45,7 @@ import com.sk89q.worldedit.CuboidClipboard; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.TileEntityBlock; -import com.sk89q.worldedit.data.DataException; +import com.sk89q.worldedit.world.DataException; /** * @author zml2008 diff --git a/src/main/java/com/sk89q/worldedit/schematic/SchematicFormat.java b/src/main/java/com/sk89q/worldedit/schematic/SchematicFormat.java index 274611167..a630cb4c3 100644 --- a/src/main/java/com/sk89q/worldedit/schematic/SchematicFormat.java +++ b/src/main/java/com/sk89q/worldedit/schematic/SchematicFormat.java @@ -30,7 +30,7 @@ import java.util.Set; import com.sk89q.worldedit.CuboidClipboard; import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.data.DataException; +import com.sk89q.worldedit.world.DataException; /** * Represents a format that a schematic can be stored as diff --git a/src/main/java/com/sk89q/worldedit/scripting/CraftScriptContext.java b/src/main/java/com/sk89q/worldedit/scripting/CraftScriptContext.java index f07ec4321..50e1ecf5f 100644 --- a/src/main/java/com/sk89q/worldedit/scripting/CraftScriptContext.java +++ b/src/main/java/com/sk89q/worldedit/scripting/CraftScriptContext.java @@ -35,7 +35,7 @@ import com.sk89q.worldedit.UnknownItemException; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.commands.InsufficientArgumentsException; +import com.sk89q.worldedit.command.InsufficientArgumentsException; import com.sk89q.worldedit.patterns.Pattern; /** diff --git a/src/main/java/com/sk89q/worldedit/session/SessionManager.java b/src/main/java/com/sk89q/worldedit/session/SessionManager.java new file mode 100644 index 000000000..5e759a192 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/session/SessionManager.java @@ -0,0 +1,197 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.session; + +import com.sk89q.worldedit.*; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Session manager for WorldEdit. + *

+ * Get a reference to one from {@link WorldEdit}. + *

+ * While this class is thread-safe, the returned session may not be. + */ +public class SessionManager { + + private final WorldEdit worldEdit; + private final HashMap sessions = new HashMap(); + + /** + * Create a new session manager. + * + * @param worldEdit a WorldEdit instance + */ + public SessionManager(WorldEdit worldEdit) { + this.worldEdit = worldEdit; + } + + /** + * Get whether a session exists for the given player. + * + * @param player the player + * @return true if a session exists + */ + public synchronized boolean contains(LocalPlayer player) { + checkNotNull(player); + return sessions.containsKey(getKey(player)); + } + + /** + * Gets the session for a player and return it if it exists, otherwise + * return null. + * + * @param player the player + * @return the session for the player, if it exists + */ + public synchronized @Nullable LocalSession find(LocalPlayer player) { + checkNotNull(player); + return sessions.get(getKey(player)); + } + + /** + * Gets the session for someone named by the given name and return it if + * it exists, otherwise return null. + * + * @param name the player's name + * @return the session for the player, if it exists + */ + public synchronized @Nullable LocalSession findByName(String name) { + checkNotNull(name); + return sessions.get(name); + } + + /** + * Get the session for a player and create one if one doesn't exist. + * + * @param player the player + * @return a session + */ + public synchronized LocalSession get(LocalPlayer player) { + checkNotNull(player); + + LocalSession session; + LocalConfiguration config = worldEdit.getConfiguration(); + + if (sessions.containsKey(player.getName())) { + session = sessions.get(player.getName()); + } else { + session = new LocalSession(config); + session.setBlockChangeLimit(config.defaultChangeLimit); + // Remember the session + sessions.put(player.getName(), session); + } + + // Set the limit on the number of blocks that an operation can + // change at once, or don't if the player has an override or there + // is no limit. There is also a default limit + int currentChangeLimit = session.getBlockChangeLimit(); + + if (!player.hasPermission("worldedit.limit.unrestricted") + && config.maxChangeLimit > -1) { + + // If the default limit is infinite but there is a maximum + // limit, make sure to not have it be overridden + if (config.defaultChangeLimit < 0) { + if (currentChangeLimit < 0 || currentChangeLimit > config.maxChangeLimit) { + session.setBlockChangeLimit(config.maxChangeLimit); + } + } else { + // Bound the change limit + int maxChangeLimit = config.maxChangeLimit; + if (currentChangeLimit == -1 || currentChangeLimit > maxChangeLimit) { + session.setBlockChangeLimit(maxChangeLimit); + } + } + } + + // Have the session use inventory if it's enabled and the player + // doesn't have an override + session.setUseInventory(config.useInventory + && !(config.useInventoryOverride + && (player.hasPermission("worldedit.inventory.unrestricted") + || (config.useInventoryCreativeOverride && player.hasCreativeMode())))); + + return session; + } + + /** + * Get the key to use in the map for a player. + * + * @param player the player + * @return the key object + */ + protected String getKey(LocalPlayer player) { + return player.getName(); + } + + /** + * Mark for expiration. + * + * @param player the player + */ + public synchronized void markforExpiration(LocalPlayer player) { + checkNotNull(player); + LocalSession session = find(player); + if (session != null) { + session.update(); + } + } + + /** + * Remove the session for the given player if one exists. + * + * @param player the player + */ + public synchronized void remove(LocalPlayer player) { + checkNotNull(player); + sessions.remove(player.getName()); + } + + /** + * Remove all sessions. + */ + public synchronized void clear() { + sessions.clear(); + } + + /** + * Remove expired sessions with the given session checker. + * + * @param checker the session checker + */ + public synchronized void removeExpired(SessionCheck checker) { + Iterator> it = sessions.entrySet().iterator(); + + while (it.hasNext()) { + Map.Entry entry = it.next(); + if (entry.getValue().hasExpired() && !checker.isOnlinePlayer(entry.getKey())) { + it.remove(); + } + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/session/request/Request.java b/src/main/java/com/sk89q/worldedit/session/request/Request.java new file mode 100644 index 000000000..58dfc9960 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/session/request/Request.java @@ -0,0 +1,116 @@ +/* + * 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.session.request; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.LocalWorld; + +import javax.annotation.Nullable; + +/** + * Describes the current request using a {@link ThreadLocal}. + */ +public final class Request { + + private static final ThreadLocal threadLocal = + new ThreadLocal() { + @Override protected Request initialValue() { + return new Request(); + } + }; + + private @Nullable LocalWorld world; + private @Nullable LocalSession session; + private @Nullable EditSession editSession; + + private Request() { + } + + /** + * Get the request world. + * + * @return the world, which may be null + */ + public @Nullable LocalWorld getWorld() { + return world; + } + + /** + * Set the request world. + * + * @param world the world, which may be null + */ + public void setWorld(@Nullable LocalWorld world) { + this.world = world; + } + + /** + * Get the request session. + * + * @return the session, which may be null + */ + public @Nullable LocalSession getSession() { + return session; + } + + /** + * Get the request session. + * + * @param session the session, which may be null + */ + public void setSession(@Nullable LocalSession session) { + this.session = session; + } + + /** + * Get the {@link EditSession}. + * + * @return the edit session, which may be null + */ + public @Nullable EditSession getEditSession() { + return editSession; + } + + /** + * Set the {@link EditSession}. + * + * @param editSession the edit session, which may be null + */ + public void setEditSession(@Nullable EditSession editSession) { + this.editSession = editSession; + } + + /** + * Get the current request, which is specific to the current thread. + * + * @return the current request + */ + public static Request request() { + return threadLocal.get(); + } + + /** + * Reset the current request and clear all fields. + */ + public static void reset() { + threadLocal.remove(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/session/request/RequestSelection.java b/src/main/java/com/sk89q/worldedit/session/request/RequestSelection.java new file mode 100644 index 000000000..1e4e60101 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/session/request/RequestSelection.java @@ -0,0 +1,150 @@ +/* + * 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.session.request; + +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.regions.NullRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionOperationException; + +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +/** + * A region that mirrors the current selection according to the current + * {@link LocalSession} and {@link LocalWorld} set on the current + * {@link Request}. + *

+ * If a selection cannot be taken, then the selection will be assumed to be + * that of a {@link NullRegion}. + */ +public class RequestSelection implements Region { + + /** + * Get the delegate region. + * + * @return the delegate region + */ + protected Region getRegion() { + LocalSession session = Request.request().getSession(); + LocalWorld world = Request.request().getWorld(); + + if (session != null && world != null) { + try { + return session.getSelection(world); + } catch (IncompleteRegionException ignored) { + } + } + + return new NullRegion(); + } + + @Override + public Vector getMinimumPoint() { + return getRegion().getMinimumPoint(); + } + + @Override + public Vector getMaximumPoint() { + return getRegion().getMaximumPoint(); + } + + @Override + public Vector getCenter() { + return getRegion().getCenter(); + } + + @Override + public int getArea() { + return getRegion().getArea(); + } + + @Override + public int getWidth() { + return getRegion().getWidth(); + } + + @Override + public int getHeight() { + return getRegion().getHeight(); + } + + @Override + public int getLength() { + return getRegion().getLength(); + } + + @Override + public void expand(Vector... changes) throws RegionOperationException { + getRegion().expand(changes); + } + + @Override + public void contract(Vector... changes) throws RegionOperationException { + getRegion().contract(changes); + } + + @Override + public void shift(Vector change) throws RegionOperationException { + getRegion().shift(change); + } + + @Override + public boolean contains(Vector pt) { + return getRegion().contains(pt); + } + + @Override + public Set getChunks() { + return getRegion().getChunks(); + } + + @Override + public Set getChunkCubes() { + return getRegion().getChunkCubes(); + } + + @Override + public LocalWorld getWorld() { + return getRegion().getWorld(); + } + + @Override + public void setWorld(LocalWorld world) { + getRegion().setWorld(world); + } + + @Override + public Region clone() { + return this; + } + + @Override + public List polygonize(int maxPoints) { + return getRegion().polygonize(maxPoints); + } + + @Override + public Iterator iterator() { + return getRegion().iterator(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/Countable.java b/src/main/java/com/sk89q/worldedit/util/Countable.java similarity index 98% rename from src/main/java/com/sk89q/worldedit/Countable.java rename to src/main/java/com/sk89q/worldedit/util/Countable.java index ddadfc66b..bd8a24a74 100644 --- a/src/main/java/com/sk89q/worldedit/Countable.java +++ b/src/main/java/com/sk89q/worldedit/util/Countable.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit; +package com.sk89q.worldedit.util; /** * diff --git a/src/main/java/com/sk89q/worldedit/LogFormat.java b/src/main/java/com/sk89q/worldedit/util/LogFormat.java similarity index 98% rename from src/main/java/com/sk89q/worldedit/LogFormat.java rename to src/main/java/com/sk89q/worldedit/util/LogFormat.java index 513f9ce94..98e11a540 100644 --- a/src/main/java/com/sk89q/worldedit/LogFormat.java +++ b/src/main/java/com/sk89q/worldedit/util/LogFormat.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit; +package com.sk89q.worldedit.util; import java.util.logging.Formatter; import java.util.logging.LogRecord; diff --git a/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java b/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java index 9edd1ec3d..f9606eb0e 100644 --- a/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java +++ b/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java @@ -32,7 +32,7 @@ import java.util.Set; import com.sk89q.util.StringUtil; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.snapshots.SnapshotRepository; +import com.sk89q.worldedit.world.snapshot.SnapshotRepository; /** * Simple LocalConfiguration that loads settings using diff --git a/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java b/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java index b15ec4d10..a5ddf9ae3 100644 --- a/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java +++ b/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java @@ -26,7 +26,7 @@ import java.util.logging.Logger; import com.sk89q.util.yaml.YAMLProcessor; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.snapshots.SnapshotRepository; +import com.sk89q.worldedit.world.snapshot.SnapshotRepository; /** * A less simple implementation of {@link LocalConfiguration} using YAML configuration files. diff --git a/src/main/java/com/sk89q/worldedit/DoubleArrayList.java b/src/main/java/com/sk89q/worldedit/util/collection/DoubleArrayList.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/DoubleArrayList.java rename to src/main/java/com/sk89q/worldedit/util/collection/DoubleArrayList.java index baf685dfc..818ae5bca 100644 --- a/src/main/java/com/sk89q/worldedit/DoubleArrayList.java +++ b/src/main/java/com/sk89q/worldedit/util/collection/DoubleArrayList.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit; +package com.sk89q.worldedit.util.collection; import java.util.List; import java.util.ArrayList; @@ -88,8 +88,8 @@ public class DoubleArrayList implements Iterable> { * * @return */ - public Iterator> iterator() { - if (isReversed) { + public Iterator> iterator(boolean reversed) { + if (reversed) { return new ReverseEntryIterator>( listA.listIterator(listA.size()), listB.listIterator(listB.size())); @@ -100,6 +100,15 @@ public class DoubleArrayList implements Iterable> { } } + /** + * Get an entry set. + * + * @return + */ + public Iterator> iterator() { + return iterator(isReversed); + } + /** * Entry iterator. * diff --git a/src/main/java/com/sk89q/worldedit/util/collection/FastListIterator.java b/src/main/java/com/sk89q/worldedit/util/collection/FastListIterator.java new file mode 100644 index 000000000..7aec4ca6b --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/collection/FastListIterator.java @@ -0,0 +1,110 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.util.collection; + +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A fast iterator for lists that uses an internal index integer + * and caches the size of the list. The size of the list cannot change + * during iteration and {@link Iterator#remove()} is not supported. + *

+ * The iterator in Java, at least in older Java versions, is very slow, + * causing a significant amount of time in operations in WorldEdit + * being spent on {@link Iterator#hasNext()}. In contrast, the iterator + * implemented by this class is very quick, as long as + * {@link List#get(int)} is fast. + * + * @param the element + */ +public class FastListIterator implements Iterator { + + private final List list; + private int index; + private final int size; + private final int increment; + + /** + * Create a new fast iterator. + * + * @param list the list + * @param index the index to start from + * @param size the size of the list + * @param increment the increment amount (i.e. 1 or -1) + */ + private FastListIterator(List list, int index, int size, int increment) { + checkNotNull(list); + checkArgument(size >= 0, "size >= 0 required"); + checkArgument(index >= 0, "index >= 0 required"); + this.list = list; + this.index = index; + this.size = size; + this.increment = increment; + } + + @Override + public boolean hasNext() { + return index >= 0 && index < size; + } + + @Override + public E next() { + if (hasNext()) { + E entry = list.get(index); + index += increment; + return entry; + } else { + throw new NoSuchElementException(); + } + } + + @Override + public void remove() { + throw new UnsupportedOperationException("Not supported"); + } + + /** + * Create a new forward iterator for the given list. + * + * @param list the list + * @param the element + * @return an iterator + */ + public static Iterator forwardIterator(List list) { + return new FastListIterator(list, 0, list.size(), 1); + } + + /** + * Create a new reverse iterator for the given list. + * + * @param list the list + * @param the element + * @return an iterator + */ + public static Iterator reverseIterator(List list) { + return new FastListIterator(list, list.size() - 1, list.size(), -1); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/collection/TupleArrayList.java b/src/main/java/com/sk89q/worldedit/util/collection/TupleArrayList.java new file mode 100644 index 000000000..69fd9e05d --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/collection/TupleArrayList.java @@ -0,0 +1,94 @@ +/* + * 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.util.collection; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Map; + +/** + * An {@link ArrayList} that takes {@link Map.Entry}-like tuples. This class + * exists for legacy reasons. + * + * @param
the first type in the tuple + * @param the second type in the tuple + */ +public class TupleArrayList extends ArrayList> { + + /** + * Add an item to the list. + * + * @param a the 'key' + * @param b the 'value' + */ + public void put(A a, B b) { + add(new Tuple(a, b)); + } + + /** + * Return an entry iterator that traverses in the reverse direction. + * + * @param reverse true to return the reverse iterator + * @return an entry iterator + */ + public Iterator> iterator(boolean reverse) { + return reverse ? reverseIterator() : iterator(); + } + + @Override + public Iterator> iterator() { + return FastListIterator.forwardIterator(this); + } + + /** + * Return an entry iterator that traverses in the reverse direction. + * + * @return an entry iterator + */ + public Iterator> reverseIterator() { + return FastListIterator.reverseIterator(this); + } + + private static class Tuple implements Map.Entry { + private A key; + private B value; + + private Tuple(A key, B value) { + this.key = key; + this.value = value; + } + + @Override + public A getKey() { + return key; + } + + @Override + public B getValue() { + return value; + } + + @Override + public B setValue(B value) { + throw new UnsupportedOperationException(); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/eventbus/AnnotatedSubscriberFinder.java b/src/main/java/com/sk89q/worldedit/util/eventbus/AnnotatedSubscriberFinder.java new file mode 100644 index 000000000..5415f2c4e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/eventbus/AnnotatedSubscriberFinder.java @@ -0,0 +1,69 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.util.eventbus; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; + +import java.lang.reflect.Method; + +/** + * A {@link SubscriberFindingStrategy} for collecting all event handler methods + * that are marked with the {@link Subscribe} annotation. + *

+ * Original for Guava, licensed under the Apache License, Version 2.0. + */ +class AnnotatedSubscriberFinder implements SubscriberFindingStrategy { + + /** + * {@inheritDoc} + * + * This implementation finds all methods marked with a {@link Subscribe} + * annotation. + */ + @Override + public Multimap, EventHandler> findAllSubscribers(Object listener) { + Multimap, EventHandler> methodsInListener = HashMultimap.create(); + Class clazz = listener.getClass(); + while (clazz != null) { + for (Method method : clazz.getMethods()) { + Subscribe annotation = method.getAnnotation(Subscribe.class); + method.setAccessible(true); + + if (annotation != null) { + Class[] parameterTypes = method.getParameterTypes(); + if (parameterTypes.length != 1) { + throw new IllegalArgumentException( + "Method " + method + " has @Subscribe annotation, but requires " + + parameterTypes.length + " arguments. Event handler methods " + + "must require a single argument."); + } + Class eventType = parameterTypes[0]; + EventHandler handler = new MethodEventHandler(annotation.priority(), listener, method); + methodsInListener.put(eventType, handler); + } + } + clazz = clazz.getSuperclass(); + } + + return methodsInListener; + } + +} \ No newline at end of file diff --git a/src/main/java/com/sk89q/worldedit/util/eventbus/EventBus.java b/src/main/java/com/sk89q/worldedit/util/eventbus/EventBus.java new file mode 100644 index 000000000..21e025a1e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/eventbus/EventBus.java @@ -0,0 +1,261 @@ +/* + * 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.util.eventbus; + +import com.google.common.base.Supplier; +import com.google.common.base.Throwables; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.collect.*; +import com.google.common.eventbus.DeadEvent; + +import java.lang.reflect.InvocationTargetException; +import java.util.*; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Dispatches events to listeners, and provides ways for listeners to register + * themselves. + *

+ * This class is based on Guava's {@link EventBus} but priority is supported + * and events are dispatched at the time of call, rather than being queued up. + * This does allow dispatching during an in-progress dispatch. + *

+ * This implementation utilizes naive synchronization on all getter and setter + * methods. Dispatch does not occur when a lock has been acquired, however. + */ +public class EventBus { + + private final Logger logger = Logger.getLogger(EventBus.class.getCanonicalName()); + + private final SetMultimap, EventHandler> handlersByType = + Multimaps.newSetMultimap(new HashMap, Collection>(), + new Supplier>() { + @Override + public Set get() { + return newHandlerSet(); + } + }); + + /** + * Strategy for finding handler methods in registered objects. Currently, + * only the {@link AnnotatedSubscriberFinder} is supported, but this is + * encapsulated for future expansion. + */ + private final SubscriberFindingStrategy finder = new AnnotatedSubscriberFinder(); + + /** + * A thread-safe cache for flattenHierarchy(). The Class class is immutable. + */ + private Cache, Set>> flattenHierarchyCache = + CacheBuilder.newBuilder() + .weakKeys() + .build(new CacheLoader, Set>>() { + @Override + public Set> load(Class concreteClass) throws Exception { + List> parents = Lists.newLinkedList(); + Set> classes = Sets.newHashSet(); + + parents.add(concreteClass); + + while (!parents.isEmpty()) { + Class clazz = parents.remove(0); + classes.add(clazz); + + Class parent = clazz.getSuperclass(); + if (parent != null) { + parents.add(parent); + } + + Collections.addAll(parents, clazz.getInterfaces()); + } + + return classes; + } + }); + + /** + * Registers the given handler for the given class to receive events. + * + * @param clazz the event class to register + * @param handler the handler to register + */ + public synchronized void subscribe(Class clazz, EventHandler handler) { + checkNotNull(clazz); + checkNotNull(handler); + handlersByType.put(clazz, handler); + } + + /** + * Registers the given handler for the given class to receive events. + * + * @param handlers a map of handlers + */ + public synchronized void subscribeAll(Multimap, EventHandler> handlers) { + checkNotNull(handlers); + handlersByType.putAll(handlers); + } + + /** + * Unregisters the given handler for the given class. + * + * @param clazz the class + * @param handler the handler + */ + public synchronized void unsubscribe(Class clazz, EventHandler handler) { + checkNotNull(clazz); + checkNotNull(handler); + handlersByType.remove(clazz, handler); + } + + /** + * Unregisters the given handlers. + * + * @param handlers a map of handlers + */ + public synchronized void unsubscribeAll(Multimap, EventHandler> handlers) { + checkNotNull(handlers); + for (Map.Entry, Collection> entry : handlers.asMap().entrySet()) { + Set currentHandlers = getHandlersForEventType(entry.getKey()); + Collection eventMethodsInListener = entry.getValue(); + + if (currentHandlers != null &&!currentHandlers.containsAll(entry.getValue())) { + currentHandlers.removeAll(eventMethodsInListener); + } + } + } + + /** + * Registers all handler methods on {@code object} to receive events. + * Handler methods are selected and classified using this EventBus's + * {@link SubscriberFindingStrategy}; the default strategy is the + * {@link AnnotatedSubscriberFinder}. + * + * @param object object whose handler methods should be registered. + */ + public void register(Object object) { + subscribeAll(finder.findAllSubscribers(object)); + } + + /** + * Unregisters all handler methods on a registered {@code object}. + * + * @param object object whose handler methods should be unregistered. + * @throws IllegalArgumentException if the object was not previously registered. + */ + public void unregister(Object object) { + unsubscribeAll(finder.findAllSubscribers(object)); + } + + /** + * Posts an event to all registered handlers. This method will return + * successfully after the event has been posted to all handlers, and + * regardless of any exceptions thrown by handlers. + * + *

If no handlers have been subscribed for {@code event}'s class, and + * {@code event} is not already a {@link DeadEvent}, it will be wrapped in a + * DeadEvent and reposted. + * + * @param event event to post. + */ + public void post(Object event) { + List dispatching = new ArrayList(); + + synchronized (this) { + Set> dispatchTypes = flattenHierarchy(event.getClass()); + + for (Class eventType : dispatchTypes) { + Set wrappers = getHandlersForEventType(eventType); + + if (wrappers != null && !wrappers.isEmpty()) { + dispatching.addAll(wrappers); + } + } + } + + Collections.sort(dispatching); + + for (EventHandler handler : dispatching) { + dispatch(event, handler); + } + } + + /** + * Dispatches {@code event} to the handler in {@code handler}. This method + * is an appropriate override point for subclasses that wish to make + * event delivery asynchronous. + * + * @param event event to dispatch. + * @param handler handler that will call the handler. + */ + protected void dispatch(Object event, EventHandler handler) { + try { + handler.handleEvent(event); + } catch (InvocationTargetException e) { + logger.log(Level.SEVERE, + "Could not dispatch event: " + event + " to handler " + handler, e); + } + } + + /** + * Retrieves a mutable set of the currently registered handlers for + * {@code type}. If no handlers are currently registered for {@code type}, + * this method may either return {@code null} or an empty set. + * + * @param type type of handlers to retrieve. + * @return currently registered handlers, or {@code null}. + */ + synchronized Set getHandlersForEventType(Class type) { + return handlersByType.get(type); + } + + /** + * Creates a new Set for insertion into the handler map. This is provided + * as an override point for subclasses. The returned set should support + * concurrent access. + * + * @return a new, mutable set for handlers. + */ + protected synchronized Set newHandlerSet() { + return new HashSet(); + } + + /** + * Flattens a class's type hierarchy into a set of Class objects. The set + * will include all superclasses (transitively), and all interfaces + * implemented by these superclasses. + * + * @param concreteClass class whose type hierarchy will be retrieved. + * @return {@code clazz}'s complete type hierarchy, flattened and uniqued. + */ + Set> flattenHierarchy(Class concreteClass) { + try { + return flattenHierarchyCache.get(concreteClass); + } catch (ExecutionException e) { + throw Throwables.propagate(e.getCause()); + } + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/eventbus/EventHandler.java b/src/main/java/com/sk89q/worldedit/util/eventbus/EventHandler.java new file mode 100644 index 000000000..1903d80e3 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/eventbus/EventHandler.java @@ -0,0 +1,105 @@ +/* + * 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.util.eventbus; + +import java.lang.reflect.InvocationTargetException; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Event handler object for {@link EventBus} that is able to dispatch + * an event. + *

+ * Original for Guava, licensed under the Apache License, Version 2.0. + */ +public abstract class EventHandler implements Comparable { + + public enum Priority { + VERY_EARLY, + EARLY, + NORMAL, + LATE, + VERY_LATE + } + + private final Priority priority; + + /** + * Create a new event handler. + * + * @param priority the priority + */ + protected EventHandler(Priority priority) { + checkNotNull(priority); + this.priority = priority; + } + + /** + * Get the priority. + * + * @return the priority + */ + public Priority getPriority() { + return priority; + } + + /** + * Dispatch the given event. + *

+ * Subclasses should override {@link #dispatch(Object)}. + * + * @param event the event + * @throws InvocationTargetException thrown if an exception is thrown during dispatch + */ + public final void handleEvent(Object event) throws InvocationTargetException { + try { + dispatch(event); + } catch (Throwable t) { + throw new InvocationTargetException(t); + } + } + + /** + * Dispatch the event. + * + * @param event the event object + * @throws Exception an exception that may be thrown + */ + public abstract void dispatch(Object event) throws Exception; + + @Override + public int compareTo(EventHandler o) { + return getPriority().ordinal() - o.getPriority().ordinal(); + } + + @Override + public abstract int hashCode(); + + @Override + public abstract boolean equals(Object obj); + + @Override + public String toString() { + return "EventHandler{" + + "priority=" + priority + + '}'; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/util/eventbus/MethodEventHandler.java b/src/main/java/com/sk89q/worldedit/util/eventbus/MethodEventHandler.java new file mode 100644 index 000000000..40f087b8c --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/eventbus/MethodEventHandler.java @@ -0,0 +1,81 @@ +/* + * 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.util.eventbus; + +import java.lang.reflect.Method; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Invokes a {@link Method} to dispatch an event. + */ +public class MethodEventHandler extends EventHandler { + + private final Object object; + private final Method method; + + /** + * Create a new event handler. + * + * @param priority the priority + * @param method the method + */ + public MethodEventHandler(Priority priority, Object object, Method method) { + super(priority); + checkNotNull(method); + this.object = object; + this.method = method; + } + + /** + * Get the method. + * + * @return the method + */ + public Method getMethod() { + return method; + } + + @Override + public void dispatch(Object event) throws Exception { + method.invoke(object, event); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + MethodEventHandler that = (MethodEventHandler) o; + + if (!method.equals(that.method)) return false; + if (object != null ? !object.equals(that.object) : that.object != null) + return false; + + return true; + } + + @Override + public int hashCode() { + int result = object != null ? object.hashCode() : 0; + result = 31 * result + method.hashCode(); + return result; + } +} diff --git a/src/main/java/com/sk89q/worldedit/util/eventbus/Subscribe.java b/src/main/java/com/sk89q/worldedit/util/eventbus/Subscribe.java new file mode 100644 index 000000000..41b8a4377 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/eventbus/Subscribe.java @@ -0,0 +1,42 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.util.eventbus; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +/** + * Used to mark methods as event handlers. + */ +@Retention(RUNTIME) +@Target({METHOD}) +public @interface Subscribe { + + /** + * The priority as far as order of dispatching is concerned. + * + * @return the priority + */ + EventHandler.Priority priority() default EventHandler.Priority.NORMAL; + +} diff --git a/src/main/java/com/sk89q/worldedit/util/eventbus/SubscriberFindingStrategy.java b/src/main/java/com/sk89q/worldedit/util/eventbus/SubscriberFindingStrategy.java new file mode 100644 index 000000000..78e470a6a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/util/eventbus/SubscriberFindingStrategy.java @@ -0,0 +1,43 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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.util.eventbus; + +import com.google.common.collect.Multimap; + +/** + * A method for finding event handler methods in objects, for use by + * {@link EventBus}. + */ +interface SubscriberFindingStrategy { + + /** + * Finds all suitable event handler methods in {@code source}, organizes them + * by the type of event they handle, and wraps them in {@link EventHandler}s. + * + * @param source object whose handlers are desired. + * @return EventHandler objects for each handler method, organized by event + * type. + * + * @throws IllegalArgumentException if {@code source} is not appropriate for + * this strategy (in ways that this interface does not define). + */ + Multimap, EventHandler> findAllSubscribers(Object source); + +} \ No newline at end of file diff --git a/src/main/java/com/sk89q/worldedit/data/ForwardSeekableInputStream.java b/src/main/java/com/sk89q/worldedit/util/io/ForwardSeekableInputStream.java similarity index 94% rename from src/main/java/com/sk89q/worldedit/data/ForwardSeekableInputStream.java rename to src/main/java/com/sk89q/worldedit/util/io/ForwardSeekableInputStream.java index d23ff34c3..cf70fb736 100644 --- a/src/main/java/com/sk89q/worldedit/data/ForwardSeekableInputStream.java +++ b/src/main/java/com/sk89q/worldedit/util/io/ForwardSeekableInputStream.java @@ -1,102 +1,102 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.data; - -import java.io.IOException; -import java.io.InputStream; - -public class ForwardSeekableInputStream extends InputStream { - - protected InputStream parent; - protected long position = 0; - - public ForwardSeekableInputStream(InputStream parent) { - this.parent = parent; - } - - @Override - public int read() throws IOException { - int ret = parent.read(); - ++position; - return ret; - } - - @Override - public int available() throws IOException { - return parent.available(); - } - - @Override - public void close() throws IOException { - parent.close(); - } - - @Override - public synchronized void mark(int readlimit) { - parent.mark(readlimit); - } - - @Override - public boolean markSupported() { - return parent.markSupported(); - } - - @Override - public int read(byte[] b, int off, int len) throws IOException { - int read = super.read(b, off, len); - position += read; - return read; - } - - @Override - public int read(byte[] b) throws IOException { - int read = parent.read(b); - position += read; - return read; - } - - @Override - public synchronized void reset() throws IOException { - parent.reset(); - } - - @Override - public long skip(long n) throws IOException { - long skipped = parent.skip(n); - position += skipped; - return skipped; - } - - public void seek(long n) throws IOException { - long diff = n - position; - - if (diff < 0) { - throw new IOException("Can't seek backwards"); - } - - if (diff == 0) { - return; - } - - if (skip(diff) < diff) { - throw new IOException("Failed to seek " + diff + " bytes"); - } - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.util.io; + +import java.io.IOException; +import java.io.InputStream; + +public class ForwardSeekableInputStream extends InputStream { + + protected InputStream parent; + protected long position = 0; + + public ForwardSeekableInputStream(InputStream parent) { + this.parent = parent; + } + + @Override + public int read() throws IOException { + int ret = parent.read(); + ++position; + return ret; + } + + @Override + public int available() throws IOException { + return parent.available(); + } + + @Override + public void close() throws IOException { + parent.close(); + } + + @Override + public synchronized void mark(int readlimit) { + parent.mark(readlimit); + } + + @Override + public boolean markSupported() { + return parent.markSupported(); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + int read = super.read(b, off, len); + position += read; + return read; + } + + @Override + public int read(byte[] b) throws IOException { + int read = parent.read(b); + position += read; + return read; + } + + @Override + public synchronized void reset() throws IOException { + parent.reset(); + } + + @Override + public long skip(long n) throws IOException { + long skipped = parent.skip(n); + position += skipped; + return skipped; + } + + public void seek(long n) throws IOException { + long diff = n - position; + + if (diff < 0) { + throw new IOException("Can't seek backwards"); + } + + if (diff == 0) { + return; + } + + if (skip(diff) < diff) { + throw new IOException("Failed to seek " + diff + " bytes"); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/data/DataException.java b/src/main/java/com/sk89q/worldedit/world/DataException.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/data/DataException.java rename to src/main/java/com/sk89q/worldedit/world/DataException.java index 535f37aac..376e9666d 100644 --- a/src/main/java/com/sk89q/worldedit/data/DataException.java +++ b/src/main/java/com/sk89q/worldedit/world/DataException.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.data; +package com.sk89q.worldedit.world; /** * Thrown when there is an exception related to data handling. diff --git a/src/main/java/com/sk89q/worldedit/foundation/NbtValued.java b/src/main/java/com/sk89q/worldedit/world/NbtValued.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/foundation/NbtValued.java rename to src/main/java/com/sk89q/worldedit/world/NbtValued.java index 89dcd2069..70410030f 100644 --- a/src/main/java/com/sk89q/worldedit/foundation/NbtValued.java +++ b/src/main/java/com/sk89q/worldedit/world/NbtValued.java @@ -16,10 +16,10 @@ * this program. If not, see . */ -package com.sk89q.worldedit.foundation; +package com.sk89q.worldedit.world; import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.data.DataException; +import com.sk89q.worldedit.world.DataException; /** * Indicates an object that contains extra data identified as an NBT structure. This diff --git a/src/main/java/com/sk89q/worldedit/foundation/World.java b/src/main/java/com/sk89q/worldedit/world/World.java similarity index 84% rename from src/main/java/com/sk89q/worldedit/foundation/World.java rename to src/main/java/com/sk89q/worldedit/world/World.java index d01a0abad..c7f250730 100644 --- a/src/main/java/com/sk89q/worldedit/foundation/World.java +++ b/src/main/java/com/sk89q/worldedit/world/World.java @@ -16,10 +16,12 @@ * this program. If not, see . */ -package com.sk89q.worldedit.foundation; +package com.sk89q.worldedit.world; import com.sk89q.worldedit.LocalWorld; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.foundation.Block; /** * Represents a world instance that can be modified. The world instance could be @@ -33,8 +35,8 @@ public interface World { /** * Change the block at the given location to the given block. The operation may - * not tie the given {@link Block} to the world, so future changes to the - * {@link Block} do not affect the world until this method is called again. + * not tie the given {@link BaseBlock} to the world, so future changes to the + * {@link BaseBlock} do not affect the world until this method is called again. *

* Implementations may or may not consider the value of the notifyAdjacent * parameter, and implementations may to choose to either apply physics anyway or @@ -47,23 +49,23 @@ public interface World { * occur and 'false' should be returned. If possible, the return value should be * accurate as possible, but implementations may choose to not provide an accurate * value if it is not possible to know. - * + * * @param location location of the block * @param block block to set * @param notifyAdjacent true to to notify adjacent (perform physics) * @return true if the block was successfully set (return value may not be accurate) */ - boolean setBlock(Vector location, Block block, boolean notifyAdjacent); - + boolean setBlock(Vector location, BaseBlock block, boolean notifyAdjacent); + /** * Get a copy of the block at the given location. May return null if the location * given is out of bounds. The returned block must not be tied to any real block * in the world, so changes to the returned {@link Block} have no effect until - * {@link #setBlock(Vector, Block, boolean)} is called. - * + * {@link #setBlock(Vector, BaseBlock, boolean)} is called. + * * @param location location of the block * @return the block, or null if the block does not exist */ - Block getBlock(Vector location); + BaseBlock getBlock(Vector location); } diff --git a/src/main/java/com/sk89q/worldedit/data/AnvilChunk.java b/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk.java similarity index 98% rename from src/main/java/com/sk89q/worldedit/data/AnvilChunk.java rename to src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk.java index 25fdf46cf..34b4a23f3 100644 --- a/src/main/java/com/sk89q/worldedit/data/AnvilChunk.java +++ b/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk.java @@ -1,4 +1,4 @@ -package com.sk89q.worldedit.data; +package com.sk89q.worldedit.world.chunk; import java.util.HashMap; import java.util.List; @@ -16,6 +16,8 @@ import com.sk89q.worldedit.LocalWorld; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.TileEntityBlock; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.storage.InvalidFormatException; public class AnvilChunk implements Chunk { diff --git a/src/main/java/com/sk89q/worldedit/data/Chunk.java b/src/main/java/com/sk89q/worldedit/world/chunk/Chunk.java similarity index 88% rename from src/main/java/com/sk89q/worldedit/data/Chunk.java rename to src/main/java/com/sk89q/worldedit/world/chunk/Chunk.java index e0fd98867..c566ea881 100644 --- a/src/main/java/com/sk89q/worldedit/data/Chunk.java +++ b/src/main/java/com/sk89q/worldedit/world/chunk/Chunk.java @@ -1,7 +1,8 @@ -package com.sk89q.worldedit.data; +package com.sk89q.worldedit.world.chunk; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.world.DataException; public interface Chunk { diff --git a/src/main/java/com/sk89q/worldedit/data/OldChunk.java b/src/main/java/com/sk89q/worldedit/world/chunk/OldChunk.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/data/OldChunk.java rename to src/main/java/com/sk89q/worldedit/world/chunk/OldChunk.java index 3a2fb8a9c..ffd9fe9ad 100644 --- a/src/main/java/com/sk89q/worldedit/data/OldChunk.java +++ b/src/main/java/com/sk89q/worldedit/world/chunk/OldChunk.java @@ -17,23 +17,20 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.data; +package com.sk89q.worldedit.world.chunk; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import com.sk89q.jnbt.ByteArrayTag; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.IntTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.NBTUtils; -import com.sk89q.jnbt.Tag; +import com.sk89q.jnbt.*; import com.sk89q.worldedit.BlockVector; import com.sk89q.worldedit.LocalWorld; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.TileEntityBlock; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.storage.InvalidFormatException; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * Represents a chunk. diff --git a/src/main/java/com/sk89q/worldedit/snapshots/InvalidSnapshotException.java b/src/main/java/com/sk89q/worldedit/world/snapshot/InvalidSnapshotException.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/snapshots/InvalidSnapshotException.java rename to src/main/java/com/sk89q/worldedit/world/snapshot/InvalidSnapshotException.java index 19af8c238..5cc922437 100644 --- a/src/main/java/com/sk89q/worldedit/snapshots/InvalidSnapshotException.java +++ b/src/main/java/com/sk89q/worldedit/world/snapshot/InvalidSnapshotException.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.snapshots; +package com.sk89q.worldedit.world.snapshot; /** * diff --git a/src/main/java/com/sk89q/worldedit/snapshots/ModificationTimerParser.java b/src/main/java/com/sk89q/worldedit/world/snapshot/ModificationTimerParser.java similarity index 93% rename from src/main/java/com/sk89q/worldedit/snapshots/ModificationTimerParser.java rename to src/main/java/com/sk89q/worldedit/world/snapshot/ModificationTimerParser.java index 1fc5aba61..c509f961b 100644 --- a/src/main/java/com/sk89q/worldedit/snapshots/ModificationTimerParser.java +++ b/src/main/java/com/sk89q/worldedit/world/snapshot/ModificationTimerParser.java @@ -1,34 +1,34 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.snapshots; - -import java.io.File; -import java.util.Calendar; -import java.util.GregorianCalendar; - -public class ModificationTimerParser implements SnapshotDateParser { - - public Calendar detectDate(File file) { - Calendar cal = new GregorianCalendar(); - cal.setTimeInMillis(file.lastModified()); - return cal; - } - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.world.snapshot; + +import java.io.File; +import java.util.Calendar; +import java.util.GregorianCalendar; + +public class ModificationTimerParser implements SnapshotDateParser { + + public Calendar detectDate(File file) { + Calendar cal = new GregorianCalendar(); + cal.setTimeInMillis(file.lastModified()); + return cal; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/snapshots/Snapshot.java b/src/main/java/com/sk89q/worldedit/world/snapshot/Snapshot.java similarity index 97% rename from src/main/java/com/sk89q/worldedit/snapshots/Snapshot.java rename to src/main/java/com/sk89q/worldedit/world/snapshot/Snapshot.java index 872d2e70a..f06bc5038 100644 --- a/src/main/java/com/sk89q/worldedit/snapshots/Snapshot.java +++ b/src/main/java/com/sk89q/worldedit/world/snapshot/Snapshot.java @@ -16,9 +16,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package com.sk89q.worldedit.snapshots; +package com.sk89q.worldedit.world.snapshot; -import com.sk89q.worldedit.data.*; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.storage.*; import java.io.File; import java.io.IOException; import java.util.Calendar; diff --git a/src/main/java/com/sk89q/worldedit/snapshots/SnapshotDateParser.java b/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotDateParser.java similarity index 93% rename from src/main/java/com/sk89q/worldedit/snapshots/SnapshotDateParser.java rename to src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotDateParser.java index 92938eb24..d5e958bb8 100644 --- a/src/main/java/com/sk89q/worldedit/snapshots/SnapshotDateParser.java +++ b/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotDateParser.java @@ -1,38 +1,38 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.snapshots; - -import java.io.File; -import java.util.Calendar; - -/** - * A name parser attempts to make sense of a filename for a snapshot. - * - * @author sk89q - */ -public interface SnapshotDateParser { - /** - * Attempt to detect a date from a file. - * - * @param file - * @return date or null - */ - public Calendar detectDate(File file); -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.world.snapshot; + +import java.io.File; +import java.util.Calendar; + +/** + * A name parser attempts to make sense of a filename for a snapshot. + * + * @author sk89q + */ +public interface SnapshotDateParser { + /** + * Attempt to detect a date from a file. + * + * @param file + * @return date or null + */ + public Calendar detectDate(File file); +} diff --git a/src/main/java/com/sk89q/worldedit/snapshots/SnapshotRepository.java b/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRepository.java similarity index 98% rename from src/main/java/com/sk89q/worldedit/snapshots/SnapshotRepository.java rename to src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRepository.java index 1ebdf8804..738b1f524 100644 --- a/src/main/java/com/sk89q/worldedit/snapshots/SnapshotRepository.java +++ b/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRepository.java @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package com.sk89q.worldedit.snapshots; +package com.sk89q.worldedit.world.snapshot; import java.io.File; import java.io.FilenameFilter; @@ -25,7 +25,7 @@ import java.util.Calendar; import java.util.Collections; import java.util.List; -import com.sk89q.worldedit.data.MissingWorldException; +import com.sk89q.worldedit.world.storage.MissingWorldException; /** * diff --git a/src/main/java/com/sk89q/worldedit/snapshots/SnapshotRestore.java b/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRestore.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/snapshots/SnapshotRestore.java rename to src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRestore.java index 5f76d3c35..081515ead 100644 --- a/src/main/java/com/sk89q/worldedit/snapshots/SnapshotRestore.java +++ b/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRestore.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.snapshots; +package com.sk89q.worldedit.world.snapshot; import java.io.IOException; import java.util.ArrayList; @@ -31,11 +31,11 @@ import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.data.Chunk; -import com.sk89q.worldedit.data.ChunkStore; -import com.sk89q.worldedit.data.DataException; -import com.sk89q.worldedit.data.MissingChunkException; -import com.sk89q.worldedit.data.MissingWorldException; +import com.sk89q.worldedit.world.chunk.Chunk; +import com.sk89q.worldedit.world.storage.ChunkStore; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.storage.MissingChunkException; +import com.sk89q.worldedit.world.storage.MissingWorldException; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; diff --git a/src/main/java/com/sk89q/worldedit/snapshots/YYMMDDHHIISSParser.java b/src/main/java/com/sk89q/worldedit/world/snapshot/YYMMDDHHIISSParser.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/snapshots/YYMMDDHHIISSParser.java rename to src/main/java/com/sk89q/worldedit/world/snapshot/YYMMDDHHIISSParser.java index 83c7fe491..cea6eb189 100644 --- a/src/main/java/com/sk89q/worldedit/snapshots/YYMMDDHHIISSParser.java +++ b/src/main/java/com/sk89q/worldedit/world/snapshot/YYMMDDHHIISSParser.java @@ -1,50 +1,50 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.snapshots; - -import java.io.File; -import java.util.Calendar; -import java.util.GregorianCalendar; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class YYMMDDHHIISSParser implements SnapshotDateParser { - - protected Pattern patt = - Pattern.compile("([0-9]+)[^0-9]?([0-9]+)[^0-9]?([0-9]+)[^0-9]?" - + "([0-9]+)[^0-9]?([0-9]+)[^0-9]?([0-9]+)"); - - public Calendar detectDate(File file) { - Matcher matcher = patt.matcher(file.getName()); - if (matcher.matches()) { - int year = Integer.parseInt(matcher.group(1)); - int month = Integer.parseInt(matcher.group(2)); - int day = Integer.parseInt(matcher.group(3)); - int hrs = Integer.parseInt(matcher.group(4)); - int min = Integer.parseInt(matcher.group(5)); - int sec = Integer.parseInt(matcher.group(6)); - Calendar calender = new GregorianCalendar(); - calender.set(year, month, day, hrs, min, sec); - return calender; - } - return null; - } - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.world.snapshot; + +import java.io.File; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class YYMMDDHHIISSParser implements SnapshotDateParser { + + protected Pattern patt = + Pattern.compile("([0-9]+)[^0-9]?([0-9]+)[^0-9]?([0-9]+)[^0-9]?" + + "([0-9]+)[^0-9]?([0-9]+)[^0-9]?([0-9]+)"); + + public Calendar detectDate(File file) { + Matcher matcher = patt.matcher(file.getName()); + if (matcher.matches()) { + int year = Integer.parseInt(matcher.group(1)); + int month = Integer.parseInt(matcher.group(2)); + int day = Integer.parseInt(matcher.group(3)); + int hrs = Integer.parseInt(matcher.group(4)); + int min = Integer.parseInt(matcher.group(5)); + int sec = Integer.parseInt(matcher.group(6)); + Calendar calender = new GregorianCalendar(); + calender.set(year, month, day, hrs, min, sec); + return calender; + } + return null; + } + +} diff --git a/src/main/java/com/sk89q/worldedit/data/BlockData.java b/src/main/java/com/sk89q/worldedit/world/storage/BlockData.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/data/BlockData.java rename to src/main/java/com/sk89q/worldedit/world/storage/BlockData.java index 62c2bc8f0..ea0fc7718 100644 --- a/src/main/java/com/sk89q/worldedit/data/BlockData.java +++ b/src/main/java/com/sk89q/worldedit/world/storage/BlockData.java @@ -1,124 +1,124 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.data; - -import com.sk89q.worldedit.CuboidClipboard.FlipDirection; - -/** - * Block data related classes. - * - * @deprecated use {@link com.sk89q.worldedit.blocks.BlockData} - * @author sk89q - */ -@Deprecated -public final class BlockData { - /** - * Rotate a block's data value 90 degrees (north->east->south->west->north); - * - * @param type - * @param data - * @return - * @deprecated use {@link com.sk89q.worldedit.blocks.BlockData#rotate90(int, int)} - */ - @Deprecated - public static int rotate90(int type, int data) { - return com.sk89q.worldedit.blocks.BlockData.rotate90(type, data); - } - - /** - * Rotate a block's data value -90 degrees (north<-east<-south<-west<-north); - * - * @param type - * @param data - * @return - * @deprecated use {@link com.sk89q.worldedit.blocks.BlockData#rotate90Reverse(int, int)} - */ - @Deprecated - public static int rotate90Reverse(int type, int data) { - return com.sk89q.worldedit.blocks.BlockData.rotate90Reverse(type, data); - } - - /** - * Flip a block's data value. - * - * @param type - * @param data - * @return - * @deprecated use return {@link com.sk89q.worldedit.blocks.BlockData#flip(int, int)} - */ - @Deprecated - public static int flip(int type, int data) { - return rotate90(type, rotate90(type, data)); - } - - /** - * Flip a block's data value. - * - * @param type - * @param data - * @param direction - * @return - * @deprecated use {@link com.sk89q.worldedit.blocks.BlockData#flip(int, int, FlipDirection)} - */ - @Deprecated - public static int flip(int type, int data, FlipDirection direction) { - return com.sk89q.worldedit.blocks.BlockData.flip(type, data, direction); - } - - /** - * Cycle a block's data value. This usually goes through some rotational pattern - * depending on the block. If it returns -1, it means the id and data specified - * do not have anything to cycle to. - * - * @param type block id to be cycled - * @param data block data value that it starts at - * @param increment whether to go forward (1) or backward (-1) in the cycle - * @return the new data value for the block - * @deprecated use {@link com.sk89q.worldedit.blocks.BlockData#cycle(int, int, int)} - */ - @Deprecated - public static int cycle(int type, int data, int increment) { - return com.sk89q.worldedit.blocks.BlockData.cycle(type, data, increment); - } - - /** - * Returns the data value for the next color of cloth in the rainbow. This - * should not be used if you want to just increment the data value. - * @param data - * @return - * @deprecated use {@link com.sk89q.worldedit.blocks.BlockData#nextClothColor(int)} - */ - @Deprecated - public static int nextClothColor(int data) { - return com.sk89q.worldedit.blocks.BlockData.nextClothColor(data); - } - - /** - * Returns the data value for the previous ext color of cloth in the rainbow. - * This should not be used if you want to just increment the data value. - * @param data - * @return - * @deprecated use {@link com.sk89q.worldedit.blocks.BlockData#prevClothColor(int)} - */ - @Deprecated - public static int prevClothColor(int data) { - return com.sk89q.worldedit.blocks.BlockData.prevClothColor(data); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.world.storage; + +import com.sk89q.worldedit.CuboidClipboard.FlipDirection; + +/** + * Block data related classes. + * + * @deprecated use {@link com.sk89q.worldedit.blocks.BlockData} + * @author sk89q + */ +@Deprecated +public final class BlockData { + /** + * Rotate a block's data value 90 degrees (north->east->south->west->north); + * + * @param type + * @param data + * @return + * @deprecated use {@link com.sk89q.worldedit.blocks.BlockData#rotate90(int, int)} + */ + @Deprecated + public static int rotate90(int type, int data) { + return com.sk89q.worldedit.blocks.BlockData.rotate90(type, data); + } + + /** + * Rotate a block's data value -90 degrees (north<-east<-south<-west<-north); + * + * @param type + * @param data + * @return + * @deprecated use {@link com.sk89q.worldedit.blocks.BlockData#rotate90Reverse(int, int)} + */ + @Deprecated + public static int rotate90Reverse(int type, int data) { + return com.sk89q.worldedit.blocks.BlockData.rotate90Reverse(type, data); + } + + /** + * Flip a block's data value. + * + * @param type + * @param data + * @return + * @deprecated use return {@link com.sk89q.worldedit.blocks.BlockData#flip(int, int)} + */ + @Deprecated + public static int flip(int type, int data) { + return rotate90(type, rotate90(type, data)); + } + + /** + * Flip a block's data value. + * + * @param type + * @param data + * @param direction + * @return + * @deprecated use {@link com.sk89q.worldedit.blocks.BlockData#flip(int, int, FlipDirection)} + */ + @Deprecated + public static int flip(int type, int data, FlipDirection direction) { + return com.sk89q.worldedit.blocks.BlockData.flip(type, data, direction); + } + + /** + * Cycle a block's data value. This usually goes through some rotational pattern + * depending on the block. If it returns -1, it means the id and data specified + * do not have anything to cycle to. + * + * @param type block id to be cycled + * @param data block data value that it starts at + * @param increment whether to go forward (1) or backward (-1) in the cycle + * @return the new data value for the block + * @deprecated use {@link com.sk89q.worldedit.blocks.BlockData#cycle(int, int, int)} + */ + @Deprecated + public static int cycle(int type, int data, int increment) { + return com.sk89q.worldedit.blocks.BlockData.cycle(type, data, increment); + } + + /** + * Returns the data value for the next color of cloth in the rainbow. This + * should not be used if you want to just increment the data value. + * @param data + * @return + * @deprecated use {@link com.sk89q.worldedit.blocks.BlockData#nextClothColor(int)} + */ + @Deprecated + public static int nextClothColor(int data) { + return com.sk89q.worldedit.blocks.BlockData.nextClothColor(data); + } + + /** + * Returns the data value for the previous ext color of cloth in the rainbow. + * This should not be used if you want to just increment the data value. + * @param data + * @return + * @deprecated use {@link com.sk89q.worldedit.blocks.BlockData#prevClothColor(int)} + */ + @Deprecated + public static int prevClothColor(int data) { + return com.sk89q.worldedit.blocks.BlockData.prevClothColor(data); + } +} diff --git a/src/main/java/com/sk89q/worldedit/data/ChunkStore.java b/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java similarity index 91% rename from src/main/java/com/sk89q/worldedit/data/ChunkStore.java rename to src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java index d977f7516..421217684 100644 --- a/src/main/java/com/sk89q/worldedit/data/ChunkStore.java +++ b/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java @@ -17,13 +17,17 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.data; +package com.sk89q.worldedit.world.storage; import java.io.IOException; import java.util.Map; import com.sk89q.jnbt.*; import com.sk89q.worldedit.*; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.chunk.AnvilChunk; +import com.sk89q.worldedit.world.chunk.Chunk; +import com.sk89q.worldedit.world.chunk.OldChunk; /** * Represents chunk storage mechanisms. diff --git a/src/main/java/com/sk89q/worldedit/data/ChunkStoreException.java b/src/main/java/com/sk89q/worldedit/world/storage/ChunkStoreException.java similarity index 91% rename from src/main/java/com/sk89q/worldedit/data/ChunkStoreException.java rename to src/main/java/com/sk89q/worldedit/world/storage/ChunkStoreException.java index 2cc4dfbda..ca2090e95 100644 --- a/src/main/java/com/sk89q/worldedit/data/ChunkStoreException.java +++ b/src/main/java/com/sk89q/worldedit/world/storage/ChunkStoreException.java @@ -17,7 +17,9 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.data; +package com.sk89q.worldedit.world.storage; + +import com.sk89q.worldedit.world.DataException; /** * diff --git a/src/main/java/com/sk89q/worldedit/data/FileLegacyChunkStore.java b/src/main/java/com/sk89q/worldedit/world/storage/FileLegacyChunkStore.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/data/FileLegacyChunkStore.java rename to src/main/java/com/sk89q/worldedit/world/storage/FileLegacyChunkStore.java index 614f2ad76..de02fcd46 100644 --- a/src/main/java/com/sk89q/worldedit/data/FileLegacyChunkStore.java +++ b/src/main/java/com/sk89q/worldedit/world/storage/FileLegacyChunkStore.java @@ -17,7 +17,9 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.data; +package com.sk89q.worldedit.world.storage; + +import com.sk89q.worldedit.world.DataException; import java.io.File; import java.io.FileInputStream; diff --git a/src/main/java/com/sk89q/worldedit/data/FileMcRegionChunkStore.java b/src/main/java/com/sk89q/worldedit/world/storage/FileMcRegionChunkStore.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/data/FileMcRegionChunkStore.java rename to src/main/java/com/sk89q/worldedit/world/storage/FileMcRegionChunkStore.java index f244da89c..82094016a 100644 --- a/src/main/java/com/sk89q/worldedit/data/FileMcRegionChunkStore.java +++ b/src/main/java/com/sk89q/worldedit/world/storage/FileMcRegionChunkStore.java @@ -1,73 +1,75 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.data; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.util.regex.Pattern; - -public class FileMcRegionChunkStore extends McRegionChunkStore { - /** - * Folder to read from. - */ - private File path; - - /** - * Create an instance. The passed path is the folder to read the - * chunk files from. - * - * @param path - */ - public FileMcRegionChunkStore(File path) { - this.path = path; - } - - @Override - protected InputStream getInputStream(String name, String world) throws IOException, - DataException { - Pattern ext = Pattern.compile(".*\\.mc[ra]$"); // allow either file extension, both work the same - File file = null; - for (File f : new File(path, "region" + File.separator).listFiles()) { - String tempName = f.getName().replaceFirst("mcr$", "mca"); // matcher only does one at a time - if (ext.matcher(f.getName()).matches() && name.equalsIgnoreCase(tempName)) { - // get full original path now - file = new File(path + File.separator + "region" + File.separator + f.getName()); - break; - } - } - - try { - if (file == null) throw new FileNotFoundException(); - return new FileInputStream(file); - } catch (FileNotFoundException e) { - throw new MissingChunkException(); - } - } - - @Override - public boolean isValid() { - return new File(path, "region").isDirectory() || - new File(path, "DIM-1" + File.separator + "region").isDirectory(); - } - -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.world.storage; + +import com.sk89q.worldedit.world.DataException; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.regex.Pattern; + +public class FileMcRegionChunkStore extends McRegionChunkStore { + /** + * Folder to read from. + */ + private File path; + + /** + * Create an instance. The passed path is the folder to read the + * chunk files from. + * + * @param path + */ + public FileMcRegionChunkStore(File path) { + this.path = path; + } + + @Override + protected InputStream getInputStream(String name, String world) throws IOException, + DataException { + Pattern ext = Pattern.compile(".*\\.mc[ra]$"); // allow either file extension, both work the same + File file = null; + for (File f : new File(path, "region" + File.separator).listFiles()) { + String tempName = f.getName().replaceFirst("mcr$", "mca"); // matcher only does one at a time + if (ext.matcher(f.getName()).matches() && name.equalsIgnoreCase(tempName)) { + // get full original path now + file = new File(path + File.separator + "region" + File.separator + f.getName()); + break; + } + } + + try { + if (file == null) throw new FileNotFoundException(); + return new FileInputStream(file); + } catch (FileNotFoundException e) { + throw new MissingChunkException(); + } + } + + @Override + public boolean isValid() { + return new File(path, "region").isDirectory() || + new File(path, "DIM-1" + File.separator + "region").isDirectory(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/data/InvalidFormatException.java b/src/main/java/com/sk89q/worldedit/world/storage/InvalidFormatException.java similarity index 91% rename from src/main/java/com/sk89q/worldedit/data/InvalidFormatException.java rename to src/main/java/com/sk89q/worldedit/world/storage/InvalidFormatException.java index 4e9c07c4a..010b23b29 100644 --- a/src/main/java/com/sk89q/worldedit/data/InvalidFormatException.java +++ b/src/main/java/com/sk89q/worldedit/world/storage/InvalidFormatException.java @@ -17,7 +17,9 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.data; +package com.sk89q.worldedit.world.storage; + +import com.sk89q.worldedit.world.DataException; /** * diff --git a/src/main/java/com/sk89q/worldedit/data/LegacyChunkStore.java b/src/main/java/com/sk89q/worldedit/world/storage/LegacyChunkStore.java similarity index 98% rename from src/main/java/com/sk89q/worldedit/data/LegacyChunkStore.java rename to src/main/java/com/sk89q/worldedit/world/storage/LegacyChunkStore.java index 2107404db..d6e66f4da 100644 --- a/src/main/java/com/sk89q/worldedit/data/LegacyChunkStore.java +++ b/src/main/java/com/sk89q/worldedit/world/storage/LegacyChunkStore.java @@ -17,12 +17,14 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.data; +package com.sk89q.worldedit.world.storage; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.NBTInputStream; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.*; +import com.sk89q.worldedit.world.DataException; + import java.io.File; import java.io.IOException; import java.io.InputStream; diff --git a/src/main/java/com/sk89q/worldedit/data/McRegionChunkStore.java b/src/main/java/com/sk89q/worldedit/world/storage/McRegionChunkStore.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/data/McRegionChunkStore.java rename to src/main/java/com/sk89q/worldedit/world/storage/McRegionChunkStore.java index 58c161f7b..428fac7d6 100644 --- a/src/main/java/com/sk89q/worldedit/data/McRegionChunkStore.java +++ b/src/main/java/com/sk89q/worldedit/world/storage/McRegionChunkStore.java @@ -1,132 +1,133 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010, 2011 sk89q 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.data; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Map; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.NBTInputStream; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.LocalWorld; -import com.sk89q.worldedit.Vector2D; - -public abstract class McRegionChunkStore extends ChunkStore { - protected String curFilename = null; - protected McRegionReader cachedReader = null; - - /** - * Get the filename of a region file. - * - * @param pos - * @return - */ - public static String getFilename(Vector2D pos) { - int x = pos.getBlockX(); - int z = pos.getBlockZ(); - - String filename = "r." + (x >> 5) + "." + (z >> 5) + ".mca"; - - return filename; - } - - protected McRegionReader getReader(Vector2D pos, String worldname) throws DataException, IOException { - String filename = getFilename(pos); - if (curFilename != null) { - if (curFilename.equals(filename)) { - return cachedReader; - } else { - try { - cachedReader.close(); - } catch (IOException e) { - } - } - } - InputStream stream = getInputStream(filename, worldname); - cachedReader = new McRegionReader(stream); - //curFilename = filename; - return cachedReader; - } - - @Override - public CompoundTag getChunkTag(Vector2D pos, LocalWorld world) throws DataException, - IOException { - - McRegionReader reader = getReader(pos, world.getName()); - - InputStream stream = reader.getChunkInputStream(pos); - NBTInputStream nbt = new NBTInputStream(stream); - Tag tag; - - try { - tag = nbt.readTag(); - if (!(tag instanceof CompoundTag)) { - throw new ChunkStoreException("CompoundTag expected for chunk; got " - + tag.getClass().getName()); - } - - Map children = (Map) ((CompoundTag) tag).getValue(); - CompoundTag rootTag = null; - - // Find Level tag - for (Map.Entry entry : children.entrySet()) { - if (entry.getKey().equals("Level")) { - if (entry.getValue() instanceof CompoundTag) { - rootTag = (CompoundTag) entry.getValue(); - break; - } else { - throw new ChunkStoreException("CompoundTag expected for 'Level'; got " - + entry.getValue().getClass().getName()); - } - } - } - - if (rootTag == null) { - throw new ChunkStoreException("Missing root 'Level' tag"); - } - - return rootTag; - } finally { - nbt.close(); - } - } - - /** - * Get the input stream for a chunk file. - * - * @param name - * @return - * @throws IOException - */ - protected abstract InputStream getInputStream(String name, String worldname) - throws IOException, DataException; - - /** - * Close resources. - * - * @throws IOException - */ - @Override - public void close() throws IOException { - if (cachedReader != null) { - cachedReader.close(); - } - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q 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.world.storage; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.NBTInputStream; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.world.DataException; + +public abstract class McRegionChunkStore extends ChunkStore { + protected String curFilename = null; + protected McRegionReader cachedReader = null; + + /** + * Get the filename of a region file. + * + * @param pos + * @return + */ + public static String getFilename(Vector2D pos) { + int x = pos.getBlockX(); + int z = pos.getBlockZ(); + + String filename = "r." + (x >> 5) + "." + (z >> 5) + ".mca"; + + return filename; + } + + protected McRegionReader getReader(Vector2D pos, String worldname) throws DataException, IOException { + String filename = getFilename(pos); + if (curFilename != null) { + if (curFilename.equals(filename)) { + return cachedReader; + } else { + try { + cachedReader.close(); + } catch (IOException e) { + } + } + } + InputStream stream = getInputStream(filename, worldname); + cachedReader = new McRegionReader(stream); + //curFilename = filename; + return cachedReader; + } + + @Override + public CompoundTag getChunkTag(Vector2D pos, LocalWorld world) throws DataException, + IOException { + + McRegionReader reader = getReader(pos, world.getName()); + + InputStream stream = reader.getChunkInputStream(pos); + NBTInputStream nbt = new NBTInputStream(stream); + Tag tag; + + try { + tag = nbt.readTag(); + if (!(tag instanceof CompoundTag)) { + throw new ChunkStoreException("CompoundTag expected for chunk; got " + + tag.getClass().getName()); + } + + Map children = (Map) ((CompoundTag) tag).getValue(); + CompoundTag rootTag = null; + + // Find Level tag + for (Map.Entry entry : children.entrySet()) { + if (entry.getKey().equals("Level")) { + if (entry.getValue() instanceof CompoundTag) { + rootTag = (CompoundTag) entry.getValue(); + break; + } else { + throw new ChunkStoreException("CompoundTag expected for 'Level'; got " + + entry.getValue().getClass().getName()); + } + } + } + + if (rootTag == null) { + throw new ChunkStoreException("Missing root 'Level' tag"); + } + + return rootTag; + } finally { + nbt.close(); + } + } + + /** + * Get the input stream for a chunk file. + * + * @param name + * @return + * @throws IOException + */ + protected abstract InputStream getInputStream(String name, String worldname) + throws IOException, DataException; + + /** + * Close resources. + * + * @throws IOException + */ + @Override + public void close() throws IOException { + if (cachedReader != null) { + cachedReader.close(); + } + } +} diff --git a/src/main/java/com/sk89q/worldedit/data/McRegionReader.java b/src/main/java/com/sk89q/worldedit/world/storage/McRegionReader.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/data/McRegionReader.java rename to src/main/java/com/sk89q/worldedit/world/storage/McRegionReader.java index 743bdfebf..07eb21f32 100644 --- a/src/main/java/com/sk89q/worldedit/data/McRegionReader.java +++ b/src/main/java/com/sk89q/worldedit/world/storage/McRegionReader.java @@ -1,202 +1,204 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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 . -*/ - -/* - - Region File Format - - Concept: The minimum unit of storage on hard drives is 4KB. 90% of Minecraft - chunks are smaller than 4KB. 99% are smaller than 8KB. Write a simple - container to store chunks in single files in runs of 4KB sectors. - - Each region file represents a 32x32 group of chunks. The conversion from - chunk number to region number is floor(coord / 32): a chunk at (30, -3) - would be in region (0, -1), and one at (70, -30) would be at (3, -1). - Region files are named "r.x.z.data", where x and z are the region coordinates. - - A region file begins with a 4KB header that describes where chunks are stored - in the file. A 4-byte big-endian integer represents sector offsets and sector - counts. The chunk offset for a chunk (x, z) begins at byte 4*(x+z*32) in the - file. The bottom byte of the chunk offset indicates the number of sectors the - chunk takes up, and the top 3 bytes represent the sector number of the chunk. - Given a chunk offset o, the chunk data begins at byte 4096*(o/256) and takes up - at most 4096*(o%256) bytes. A chunk cannot exceed 1MB in size. If a chunk - offset is 0, the corresponding chunk is not stored in the region file. - - Chunk data begins with a 4-byte big-endian integer representing the chunk data - length in bytes, not counting the length field. The length must be smaller than - 4096 times the number of sectors. The next byte is a version field, to allow - backwards-compatible updates to how chunks are encoded. - - A version of 1 represents a gzipped NBT file. The gzipped data is the chunk - length - 1. - - A version of 2 represents a deflated (zlib compressed) NBT file. The deflated - data is the chunk length - 1. - - */ - -package com.sk89q.worldedit.data; - -import java.io.ByteArrayInputStream; -import java.io.DataInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.zip.GZIPInputStream; -import java.util.zip.InflaterInputStream; - -import com.sk89q.worldedit.Vector2D; - -/** - * Reader for a MCRegion file. This reader works on input streams, meaning - * that it can be used to read files from non-file based sources. - * - * @author sk89q - */ -public class McRegionReader { - - protected static final int VERSION_GZIP = 1; - protected static final int VERSION_DEFLATE = 2; - protected static final int SECTOR_BYTES = 4096; - protected static final int SECTOR_INTS = SECTOR_BYTES / 4; - public static final int CHUNK_HEADER_SIZE = 5; - - protected ForwardSeekableInputStream stream; - protected DataInputStream dataStream; - - protected int offsets[]; - - /** - * Construct the reader. - * - * @param stream - * @throws DataException - * @throws IOException - */ - public McRegionReader(InputStream stream) throws DataException, IOException { - this.stream = new ForwardSeekableInputStream(stream); - this.dataStream = new DataInputStream(this.stream); - - readHeader(); - } - - /** - * Read the header. - * - * @throws DataException - * @throws IOException - */ - private void readHeader() throws DataException, IOException { - offsets = new int[SECTOR_INTS]; - - for (int i = 0; i < SECTOR_INTS; ++i) { - int offset = dataStream.readInt(); - offsets[i] = offset; - } - } - - /** - * Gets the uncompressed data input stream for a chunk. - * - * @param pos - * @return - * @throws IOException - * @throws DataException - */ - public synchronized InputStream getChunkInputStream(Vector2D pos) - throws IOException, DataException { - - int x = pos.getBlockX() & 31; - int z = pos.getBlockZ() & 31; - - if (x < 0 || x >= 32 || z < 0 || z >= 32) { - throw new DataException("MCRegion file does not contain " + x + "," + z); - } - - int offset = getOffset(x, z); - - // The chunk hasn't been generated - if (offset == 0) { - throw new DataException("The chunk at " + x + "," + z + " is not generated"); - } - - int sectorNumber = offset >> 8; - int numSectors = offset & 0xFF; - - stream.seek(sectorNumber * SECTOR_BYTES); - int length = dataStream.readInt(); - - if (length > SECTOR_BYTES * numSectors) { - throw new DataException("MCRegion chunk at " - + x + "," + z + " has an invalid length of " + length); - } - - byte version = dataStream.readByte(); - - if (version == VERSION_GZIP) { - byte[] data = new byte[length - 1]; - if (dataStream.read(data) < length - 1) { - throw new DataException("MCRegion file does not contain " - + x + "," + z + " in full"); - } - return new GZIPInputStream(new ByteArrayInputStream(data)); - } else if (version == VERSION_DEFLATE) { - byte[] data = new byte[length - 1]; - if (dataStream.read(data) < length - 1) { - throw new DataException("MCRegion file does not contain " - + x + "," + z + " in full"); - } - return new InflaterInputStream(new ByteArrayInputStream(data)); - } else { - throw new DataException("MCRegion chunk at " - + x + "," + z + " has an unsupported version of " + version); - } - } - - /** - * Get the offset for a chunk. May return 0 if it doesn't exist. - * - * @param x - * @param z - * @return - */ - private int getOffset(int x, int z) { - return offsets[x + z * 32]; - } - - /** - * Returns whether the file contains a chunk. - * - * @param x - * @param z - * @return - */ - public boolean hasChunk(int x, int z) { - return getOffset(x, z) != 0; - } - - /** - * Close the stream. - * - * @throws IOException - */ - public void close() throws IOException { - stream.close(); - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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 . +*/ + +/* + + Region File Format + + Concept: The minimum unit of storage on hard drives is 4KB. 90% of Minecraft + chunks are smaller than 4KB. 99% are smaller than 8KB. Write a simple + container to store chunks in single files in runs of 4KB sectors. + + Each region file represents a 32x32 group of chunks. The conversion from + chunk number to region number is floor(coord / 32): a chunk at (30, -3) + would be in region (0, -1), and one at (70, -30) would be at (3, -1). + Region files are named "r.x.z.data", where x and z are the region coordinates. + + A region file begins with a 4KB header that describes where chunks are stored + in the file. A 4-byte big-endian integer represents sector offsets and sector + counts. The chunk offset for a chunk (x, z) begins at byte 4*(x+z*32) in the + file. The bottom byte of the chunk offset indicates the number of sectors the + chunk takes up, and the top 3 bytes represent the sector number of the chunk. + Given a chunk offset o, the chunk data begins at byte 4096*(o/256) and takes up + at most 4096*(o%256) bytes. A chunk cannot exceed 1MB in size. If a chunk + offset is 0, the corresponding chunk is not stored in the region file. + + Chunk data begins with a 4-byte big-endian integer representing the chunk data + length in bytes, not counting the length field. The length must be smaller than + 4096 times the number of sectors. The next byte is a version field, to allow + backwards-compatible updates to how chunks are encoded. + + A version of 1 represents a gzipped NBT file. The gzipped data is the chunk + length - 1. + + A version of 2 represents a deflated (zlib compressed) NBT file. The deflated + data is the chunk length - 1. + + */ + +package com.sk89q.worldedit.world.storage; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.zip.GZIPInputStream; +import java.util.zip.InflaterInputStream; + +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.util.io.ForwardSeekableInputStream; +import com.sk89q.worldedit.world.DataException; + +/** + * Reader for a MCRegion file. This reader works on input streams, meaning + * that it can be used to read files from non-file based sources. + * + * @author sk89q + */ +public class McRegionReader { + + protected static final int VERSION_GZIP = 1; + protected static final int VERSION_DEFLATE = 2; + protected static final int SECTOR_BYTES = 4096; + protected static final int SECTOR_INTS = SECTOR_BYTES / 4; + public static final int CHUNK_HEADER_SIZE = 5; + + protected ForwardSeekableInputStream stream; + protected DataInputStream dataStream; + + protected int offsets[]; + + /** + * Construct the reader. + * + * @param stream + * @throws DataException + * @throws IOException + */ + public McRegionReader(InputStream stream) throws DataException, IOException { + this.stream = new ForwardSeekableInputStream(stream); + this.dataStream = new DataInputStream(this.stream); + + readHeader(); + } + + /** + * Read the header. + * + * @throws DataException + * @throws IOException + */ + private void readHeader() throws DataException, IOException { + offsets = new int[SECTOR_INTS]; + + for (int i = 0; i < SECTOR_INTS; ++i) { + int offset = dataStream.readInt(); + offsets[i] = offset; + } + } + + /** + * Gets the uncompressed data input stream for a chunk. + * + * @param pos + * @return + * @throws IOException + * @throws DataException + */ + public synchronized InputStream getChunkInputStream(Vector2D pos) + throws IOException, DataException { + + int x = pos.getBlockX() & 31; + int z = pos.getBlockZ() & 31; + + if (x < 0 || x >= 32 || z < 0 || z >= 32) { + throw new DataException("MCRegion file does not contain " + x + "," + z); + } + + int offset = getOffset(x, z); + + // The chunk hasn't been generated + if (offset == 0) { + throw new DataException("The chunk at " + x + "," + z + " is not generated"); + } + + int sectorNumber = offset >> 8; + int numSectors = offset & 0xFF; + + stream.seek(sectorNumber * SECTOR_BYTES); + int length = dataStream.readInt(); + + if (length > SECTOR_BYTES * numSectors) { + throw new DataException("MCRegion chunk at " + + x + "," + z + " has an invalid length of " + length); + } + + byte version = dataStream.readByte(); + + if (version == VERSION_GZIP) { + byte[] data = new byte[length - 1]; + if (dataStream.read(data) < length - 1) { + throw new DataException("MCRegion file does not contain " + + x + "," + z + " in full"); + } + return new GZIPInputStream(new ByteArrayInputStream(data)); + } else if (version == VERSION_DEFLATE) { + byte[] data = new byte[length - 1]; + if (dataStream.read(data) < length - 1) { + throw new DataException("MCRegion file does not contain " + + x + "," + z + " in full"); + } + return new InflaterInputStream(new ByteArrayInputStream(data)); + } else { + throw new DataException("MCRegion chunk at " + + x + "," + z + " has an unsupported version of " + version); + } + } + + /** + * Get the offset for a chunk. May return 0 if it doesn't exist. + * + * @param x + * @param z + * @return + */ + private int getOffset(int x, int z) { + return offsets[x + z * 32]; + } + + /** + * Returns whether the file contains a chunk. + * + * @param x + * @param z + * @return + */ + public boolean hasChunk(int x, int z) { + return getOffset(x, z) != 0; + } + + /** + * Close the stream. + * + * @throws IOException + */ + public void close() throws IOException { + stream.close(); + } +} diff --git a/src/main/java/com/sk89q/worldedit/data/MissingChunkException.java b/src/main/java/com/sk89q/worldedit/world/storage/MissingChunkException.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/data/MissingChunkException.java rename to src/main/java/com/sk89q/worldedit/world/storage/MissingChunkException.java index 1f9ef31c7..135c53163 100644 --- a/src/main/java/com/sk89q/worldedit/data/MissingChunkException.java +++ b/src/main/java/com/sk89q/worldedit/world/storage/MissingChunkException.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.data; +package com.sk89q.worldedit.world.storage; import com.sk89q.worldedit.Vector2D; diff --git a/src/main/java/com/sk89q/worldedit/data/MissingWorldException.java b/src/main/java/com/sk89q/worldedit/world/storage/MissingWorldException.java similarity index 97% rename from src/main/java/com/sk89q/worldedit/data/MissingWorldException.java rename to src/main/java/com/sk89q/worldedit/world/storage/MissingWorldException.java index 453c74bd0..a21cba34c 100644 --- a/src/main/java/com/sk89q/worldedit/data/MissingWorldException.java +++ b/src/main/java/com/sk89q/worldedit/world/storage/MissingWorldException.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.data; +package com.sk89q.worldedit.world.storage; /** * diff --git a/src/main/java/com/sk89q/worldedit/data/TrueZipLegacyChunkStore.java b/src/main/java/com/sk89q/worldedit/world/storage/TrueZipLegacyChunkStore.java similarity index 98% rename from src/main/java/com/sk89q/worldedit/data/TrueZipLegacyChunkStore.java rename to src/main/java/com/sk89q/worldedit/world/storage/TrueZipLegacyChunkStore.java index af8018897..b6242c763 100644 --- a/src/main/java/com/sk89q/worldedit/data/TrueZipLegacyChunkStore.java +++ b/src/main/java/com/sk89q/worldedit/world/storage/TrueZipLegacyChunkStore.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.data; +package com.sk89q.worldedit.world.storage; import java.io.File; import java.io.IOException; @@ -25,6 +25,8 @@ import java.io.InputStream; import java.util.regex.Pattern; import java.util.zip.ZipException; import java.util.Enumeration; + +import com.sk89q.worldedit.world.DataException; import de.schlichtherle.util.zip.ZipEntry; import de.schlichtherle.util.zip.ZipFile; diff --git a/src/main/java/com/sk89q/worldedit/data/TrueZipMcRegionChunkStore.java b/src/main/java/com/sk89q/worldedit/world/storage/TrueZipMcRegionChunkStore.java similarity index 96% rename from src/main/java/com/sk89q/worldedit/data/TrueZipMcRegionChunkStore.java rename to src/main/java/com/sk89q/worldedit/world/storage/TrueZipMcRegionChunkStore.java index 201cfd053..ac954e756 100644 --- a/src/main/java/com/sk89q/worldedit/data/TrueZipMcRegionChunkStore.java +++ b/src/main/java/com/sk89q/worldedit/world/storage/TrueZipMcRegionChunkStore.java @@ -1,174 +1,176 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.data; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.regex.Pattern; -import java.util.zip.ZipException; -import java.util.Enumeration; -import de.schlichtherle.util.zip.ZipEntry; -import de.schlichtherle.util.zip.ZipFile; - -/** - * Represents the chunk store used by Minecraft but zipped. Uses - * the replacement classes for java.util.zip.* from TrueZip. - * - * @author sk89q - */ -public class TrueZipMcRegionChunkStore extends McRegionChunkStore { - - /** - * ZIP file. - */ - protected File zipFile; - /** - * Actual ZIP. - */ - protected ZipFile zip; - /** - * Folder inside the ZIP file to read from, if any. - */ - protected String folder; - - /** - * Create an instance. The folder argument lets you choose a folder or - * path to look into in the ZIP for the files. Use a blank string for - * the folder to not look into a subdirectory. - * - * @param zipFile - * @param folder - * @throws IOException - * @throws ZipException - */ - public TrueZipMcRegionChunkStore(File zipFile, String folder) - throws IOException, ZipException { - this.zipFile = zipFile; - this.folder = folder; - - zip = new ZipFile(zipFile); - } - - /** - * Create an instance. The subfolder containing the chunk data will - * be detected. - * - * @param zipFile - * @throws IOException - * @throws ZipException - */ - public TrueZipMcRegionChunkStore(File zipFile) - throws IOException, ZipException { - this.zipFile = zipFile; - - zip = new ZipFile(zipFile); - } - - /** - * Get the input stream for a chunk file. - * - * @param name - * @return - * @throws IOException - * @throws DataException - */ - @Override - @SuppressWarnings("unchecked") - protected InputStream getInputStream(String name, String worldname) - throws IOException, DataException { - - // Detect subfolder for the world's files - if (folder != null) { - if (!folder.equals("")) { - name = folder + "/" + name; - } - } else { - Pattern pattern = Pattern.compile(".*\\.mc[ra]$"); - // World pattern - Pattern worldPattern = Pattern.compile(worldname + "\\$"); - for (Enumeration e = zip.entries(); e.hasMoreElements(); ) { - ZipEntry testEntry = (ZipEntry) e.nextElement(); - // Check for world - if (worldPattern.matcher(worldname).matches()) { - // Check for file - if (pattern.matcher(testEntry.getName()).matches()) { - folder = testEntry.getName().substring(0, testEntry.getName().lastIndexOf("/")); - name = folder + "/" + name; - break; - } - } - } - - // Check if world is found - if (folder == null) { - throw new MissingWorldException("Target world is not present in ZIP.", worldname); - } - } - - ZipEntry entry = getEntry(name); - if (entry == null) { - throw new MissingChunkException(); - } - try { - return zip.getInputStream(entry); - } catch (ZipException e) { - throw new IOException("Failed to read " + name + " in ZIP"); - } - } - - /** - * Get an entry from the ZIP, trying both types of slashes. - * - * @param file - * @return - */ - private ZipEntry getEntry(String file) { - ZipEntry entry = zip.getEntry(file); - if (entry != null) { - return entry; - } - return zip.getEntry(file.replace("/", "\\")); - } - - /** - * Close resources. - * - * @throws IOException - */ - @Override - public void close() throws IOException { - zip.close(); - } - - @Override - @SuppressWarnings("unchecked") - public boolean isValid() { - for (Enumeration e = zip.entries(); e.hasMoreElements(); ) { - - ZipEntry testEntry = e.nextElement(); - - if (testEntry.getName().matches(".*\\.mcr$") || testEntry.getName().matches(".*\\.mca$")) { // TODO: does this need a separate class? - return true; - } - } - - return false; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.world.storage; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.regex.Pattern; +import java.util.zip.ZipException; +import java.util.Enumeration; + +import com.sk89q.worldedit.world.DataException; +import de.schlichtherle.util.zip.ZipEntry; +import de.schlichtherle.util.zip.ZipFile; + +/** + * Represents the chunk store used by Minecraft but zipped. Uses + * the replacement classes for java.util.zip.* from TrueZip. + * + * @author sk89q + */ +public class TrueZipMcRegionChunkStore extends McRegionChunkStore { + + /** + * ZIP file. + */ + protected File zipFile; + /** + * Actual ZIP. + */ + protected ZipFile zip; + /** + * Folder inside the ZIP file to read from, if any. + */ + protected String folder; + + /** + * Create an instance. The folder argument lets you choose a folder or + * path to look into in the ZIP for the files. Use a blank string for + * the folder to not look into a subdirectory. + * + * @param zipFile + * @param folder + * @throws IOException + * @throws ZipException + */ + public TrueZipMcRegionChunkStore(File zipFile, String folder) + throws IOException, ZipException { + this.zipFile = zipFile; + this.folder = folder; + + zip = new ZipFile(zipFile); + } + + /** + * Create an instance. The subfolder containing the chunk data will + * be detected. + * + * @param zipFile + * @throws IOException + * @throws ZipException + */ + public TrueZipMcRegionChunkStore(File zipFile) + throws IOException, ZipException { + this.zipFile = zipFile; + + zip = new ZipFile(zipFile); + } + + /** + * Get the input stream for a chunk file. + * + * @param name + * @return + * @throws IOException + * @throws DataException + */ + @Override + @SuppressWarnings("unchecked") + protected InputStream getInputStream(String name, String worldname) + throws IOException, DataException { + + // Detect subfolder for the world's files + if (folder != null) { + if (!folder.equals("")) { + name = folder + "/" + name; + } + } else { + Pattern pattern = Pattern.compile(".*\\.mc[ra]$"); + // World pattern + Pattern worldPattern = Pattern.compile(worldname + "\\$"); + for (Enumeration e = zip.entries(); e.hasMoreElements(); ) { + ZipEntry testEntry = (ZipEntry) e.nextElement(); + // Check for world + if (worldPattern.matcher(worldname).matches()) { + // Check for file + if (pattern.matcher(testEntry.getName()).matches()) { + folder = testEntry.getName().substring(0, testEntry.getName().lastIndexOf("/")); + name = folder + "/" + name; + break; + } + } + } + + // Check if world is found + if (folder == null) { + throw new MissingWorldException("Target world is not present in ZIP.", worldname); + } + } + + ZipEntry entry = getEntry(name); + if (entry == null) { + throw new MissingChunkException(); + } + try { + return zip.getInputStream(entry); + } catch (ZipException e) { + throw new IOException("Failed to read " + name + " in ZIP"); + } + } + + /** + * Get an entry from the ZIP, trying both types of slashes. + * + * @param file + * @return + */ + private ZipEntry getEntry(String file) { + ZipEntry entry = zip.getEntry(file); + if (entry != null) { + return entry; + } + return zip.getEntry(file.replace("/", "\\")); + } + + /** + * Close resources. + * + * @throws IOException + */ + @Override + public void close() throws IOException { + zip.close(); + } + + @Override + @SuppressWarnings("unchecked") + public boolean isValid() { + for (Enumeration e = zip.entries(); e.hasMoreElements(); ) { + + ZipEntry testEntry = e.nextElement(); + + if (testEntry.getName().matches(".*\\.mcr$") || testEntry.getName().matches(".*\\.mca$")) { // TODO: does this need a separate class? + return true; + } + } + + return false; + } +} diff --git a/src/main/java/com/sk89q/worldedit/data/ZippedLegacyChunkStore.java b/src/main/java/com/sk89q/worldedit/world/storage/ZippedLegacyChunkStore.java similarity index 98% rename from src/main/java/com/sk89q/worldedit/data/ZippedLegacyChunkStore.java rename to src/main/java/com/sk89q/worldedit/world/storage/ZippedLegacyChunkStore.java index 076be1ead..8fedcbd43 100644 --- a/src/main/java/com/sk89q/worldedit/data/ZippedLegacyChunkStore.java +++ b/src/main/java/com/sk89q/worldedit/world/storage/ZippedLegacyChunkStore.java @@ -17,7 +17,9 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.data; +package com.sk89q.worldedit.world.storage; + +import com.sk89q.worldedit.world.DataException; import java.io.File; import java.io.IOException; diff --git a/src/main/java/com/sk89q/worldedit/data/ZippedMcRegionChunkStore.java b/src/main/java/com/sk89q/worldedit/world/storage/ZippedMcRegionChunkStore.java similarity index 95% rename from src/main/java/com/sk89q/worldedit/data/ZippedMcRegionChunkStore.java rename to src/main/java/com/sk89q/worldedit/world/storage/ZippedMcRegionChunkStore.java index 5c1e64d81..daa4714f6 100644 --- a/src/main/java/com/sk89q/worldedit/data/ZippedMcRegionChunkStore.java +++ b/src/main/java/com/sk89q/worldedit/world/storage/ZippedMcRegionChunkStore.java @@ -1,169 +1,171 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q 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.data; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.regex.Pattern; -import java.util.zip.ZipEntry; -import java.util.zip.ZipException; -import java.util.zip.ZipFile; -import java.util.Enumeration; - -/** - * Represents the chunk store used by Minecraft alpha but zipped. - * - * @author sk89q - */ -public class ZippedMcRegionChunkStore extends McRegionChunkStore { - - /** - * ZIP file. - */ - protected File zipFile; - /** - * Actual ZIP. - */ - protected ZipFile zip; - /** - * Folder inside the ZIP file to read from, if any. - */ - protected String folder; - - /** - * Create an instance. The folder argument lets you choose a folder or - * path to look into in the ZIP for the files. Use a blank string for - * the folder to not look into a subdirectory. - * - * @param zipFile - * @param folder - * @throws IOException - * @throws ZipException - */ - public ZippedMcRegionChunkStore(File zipFile, String folder) - throws IOException, ZipException { - this.zipFile = zipFile; - this.folder = folder; - - zip = new ZipFile(zipFile); - } - - /** - * Create an instance. The subfolder containing the chunk data will - * be detected. - * - * @param zipFile - * @throws IOException - * @throws ZipException - */ - public ZippedMcRegionChunkStore(File zipFile) - throws IOException, ZipException { - this.zipFile = zipFile; - - zip = new ZipFile(zipFile); - } - - /** - * Get the input stream for a chunk file. - * - * @param name - * @return - * @throws IOException - * @throws DataException - */ - @Override - protected InputStream getInputStream(String name, String worldname) - throws IOException, DataException { - - // Detect subfolder for the world's files - if (folder != null) { - if (!folder.equals("")) { - name = folder + "/" + name; - } - } else { - Pattern pattern = Pattern.compile(".*\\.mc[ra]$"); - for (Enumeration e = zip.entries(); e.hasMoreElements(); ) { - ZipEntry testEntry = (ZipEntry) e.nextElement(); - // Check for world - if (testEntry.getName().startsWith(worldname + "/")) { - if (pattern.matcher(testEntry.getName()).matches()) { // does entry end in .mca - folder = testEntry.getName().substring(0, testEntry.getName().lastIndexOf("/")); - name = folder + "/" + name; - break; - } - - } - } - - // Check if world is found - if (folder == null) { - throw new MissingWorldException("Target world is not present in ZIP.", worldname); - } - } - - ZipEntry entry = getEntry(name); - if (entry == null) { - throw new MissingChunkException(); - } - try { - return zip.getInputStream(entry); - } catch (ZipException e) { - throw new IOException("Failed to read " + name + " in ZIP"); - } - } - - /** - * Get an entry from the ZIP, trying both types of slashes. - * - * @param file - * @return - */ - private ZipEntry getEntry(String file) { - ZipEntry entry = zip.getEntry(file); - if (entry != null) { - return entry; - } - return zip.getEntry(file.replace("/", "\\")); - } - - /** - * Close resources. - * - * @throws IOException - */ - @Override - public void close() throws IOException { - zip.close(); - } - - @Override - public boolean isValid() { - for (Enumeration e = zip.entries(); e.hasMoreElements(); ) { - - ZipEntry testEntry = e.nextElement(); - - if (testEntry.getName().matches(".*\\.mcr$") || testEntry.getName().matches(".*\\.mca$")) { // TODO: does this need a separate class? - return true; - } - } - - return false; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q 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.world.storage; + +import com.sk89q.worldedit.world.DataException; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.regex.Pattern; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; +import java.util.Enumeration; + +/** + * Represents the chunk store used by Minecraft alpha but zipped. + * + * @author sk89q + */ +public class ZippedMcRegionChunkStore extends McRegionChunkStore { + + /** + * ZIP file. + */ + protected File zipFile; + /** + * Actual ZIP. + */ + protected ZipFile zip; + /** + * Folder inside the ZIP file to read from, if any. + */ + protected String folder; + + /** + * Create an instance. The folder argument lets you choose a folder or + * path to look into in the ZIP for the files. Use a blank string for + * the folder to not look into a subdirectory. + * + * @param zipFile + * @param folder + * @throws IOException + * @throws ZipException + */ + public ZippedMcRegionChunkStore(File zipFile, String folder) + throws IOException, ZipException { + this.zipFile = zipFile; + this.folder = folder; + + zip = new ZipFile(zipFile); + } + + /** + * Create an instance. The subfolder containing the chunk data will + * be detected. + * + * @param zipFile + * @throws IOException + * @throws ZipException + */ + public ZippedMcRegionChunkStore(File zipFile) + throws IOException, ZipException { + this.zipFile = zipFile; + + zip = new ZipFile(zipFile); + } + + /** + * Get the input stream for a chunk file. + * + * @param name + * @return + * @throws IOException + * @throws DataException + */ + @Override + protected InputStream getInputStream(String name, String worldname) + throws IOException, DataException { + + // Detect subfolder for the world's files + if (folder != null) { + if (!folder.equals("")) { + name = folder + "/" + name; + } + } else { + Pattern pattern = Pattern.compile(".*\\.mc[ra]$"); + for (Enumeration e = zip.entries(); e.hasMoreElements(); ) { + ZipEntry testEntry = (ZipEntry) e.nextElement(); + // Check for world + if (testEntry.getName().startsWith(worldname + "/")) { + if (pattern.matcher(testEntry.getName()).matches()) { // does entry end in .mca + folder = testEntry.getName().substring(0, testEntry.getName().lastIndexOf("/")); + name = folder + "/" + name; + break; + } + + } + } + + // Check if world is found + if (folder == null) { + throw new MissingWorldException("Target world is not present in ZIP.", worldname); + } + } + + ZipEntry entry = getEntry(name); + if (entry == null) { + throw new MissingChunkException(); + } + try { + return zip.getInputStream(entry); + } catch (ZipException e) { + throw new IOException("Failed to read " + name + " in ZIP"); + } + } + + /** + * Get an entry from the ZIP, trying both types of slashes. + * + * @param file + * @return + */ + private ZipEntry getEntry(String file) { + ZipEntry entry = zip.getEntry(file); + if (entry != null) { + return entry; + } + return zip.getEntry(file.replace("/", "\\")); + } + + /** + * Close resources. + * + * @throws IOException + */ + @Override + public void close() throws IOException { + zip.close(); + } + + @Override + public boolean isValid() { + for (Enumeration e = zip.entries(); e.hasMoreElements(); ) { + + ZipEntry testEntry = e.nextElement(); + + if (testEntry.getName().matches(".*\\.mcr$") || testEntry.getName().matches(".*\\.mca$")) { // TODO: does this need a separate class? + return true; + } + } + + return false; + } +} diff --git a/src/spout/java/com/sk89q/worldedit/spout/SpoutCommandSender.java b/src/spout/java/com/sk89q/worldedit/spout/SpoutCommandSender.java index 899618062..0a84e5819 100644 --- a/src/spout/java/com/sk89q/worldedit/spout/SpoutCommandSender.java +++ b/src/spout/java/com/sk89q/worldedit/spout/SpoutCommandSender.java @@ -27,7 +27,7 @@ import com.sk89q.worldedit.PlayerNeededException; import com.sk89q.worldedit.ServerInterface; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldVector; -import com.sk89q.worldedit.bags.BlockBag; +import com.sk89q.worldedit.extent.inventory.BlockBag; import org.spout.api.chat.style.ChatStyle; import org.spout.api.command.CommandSource; import org.spout.api.entity.Player; diff --git a/src/spout/java/com/sk89q/worldedit/spout/SpoutPlayer.java b/src/spout/java/com/sk89q/worldedit/spout/SpoutPlayer.java index de9f73089..325e7551c 100644 --- a/src/spout/java/com/sk89q/worldedit/spout/SpoutPlayer.java +++ b/src/spout/java/com/sk89q/worldedit/spout/SpoutPlayer.java @@ -26,8 +26,8 @@ import com.sk89q.worldedit.LocalWorld; import com.sk89q.worldedit.ServerInterface; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldVector; -import com.sk89q.worldedit.bags.BlockBag; -import com.sk89q.worldedit.cui.CUIEvent; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.internal.cui.CUIEvent; import org.spout.api.Client; import org.spout.api.chat.style.ChatStyle; diff --git a/src/spout/java/com/sk89q/worldedit/spout/SpoutPlayerBlockBag.java b/src/spout/java/com/sk89q/worldedit/spout/SpoutPlayerBlockBag.java index 9da5ab045..9e23acd0a 100644 --- a/src/spout/java/com/sk89q/worldedit/spout/SpoutPlayerBlockBag.java +++ b/src/spout/java/com/sk89q/worldedit/spout/SpoutPlayerBlockBag.java @@ -22,13 +22,12 @@ package com.sk89q.worldedit.spout; import com.sk89q.worldedit.WorldVector; -import com.sk89q.worldedit.bags.BlockBag; -import com.sk89q.worldedit.bags.BlockBagException; -import com.sk89q.worldedit.bags.OutOfBlocksException; -import com.sk89q.worldedit.bags.OutOfSpaceException; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.extent.inventory.BlockBagException; +import com.sk89q.worldedit.extent.inventory.OutOfBlocksException; +import com.sk89q.worldedit.extent.inventory.OutOfSpaceException; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; -import com.sk89q.worldedit.blocks.BlockID; import org.spout.api.inventory.Inventory; import org.spout.api.inventory.ItemStack; import org.spout.api.material.Material; diff --git a/src/spout/java/com/sk89q/worldedit/spout/WorldEditCUIMessage.java b/src/spout/java/com/sk89q/worldedit/spout/WorldEditCUIMessage.java index ccc8ae5ac..71096ada3 100644 --- a/src/spout/java/com/sk89q/worldedit/spout/WorldEditCUIMessage.java +++ b/src/spout/java/com/sk89q/worldedit/spout/WorldEditCUIMessage.java @@ -19,7 +19,7 @@ package com.sk89q.worldedit.spout; import com.sk89q.util.StringUtil; -import com.sk89q.worldedit.cui.CUIEvent; +import com.sk89q.worldedit.internal.cui.CUIEvent; import org.apache.commons.lang3.builder.ToStringBuilder; import org.spout.api.protocol.Message; import org.spout.api.util.SpoutToStringStyle; diff --git a/src/spout/java/com/sk89q/worldedit/spout/WorldEditPlugin.java b/src/spout/java/com/sk89q/worldedit/spout/WorldEditPlugin.java index b9781e418..05b63ebc6 100644 --- a/src/spout/java/com/sk89q/worldedit/spout/WorldEditPlugin.java +++ b/src/spout/java/com/sk89q/worldedit/spout/WorldEditPlugin.java @@ -23,11 +23,11 @@ package com.sk89q.worldedit.spout; import com.sk89q.util.yaml.YAMLProcessor; import com.sk89q.worldedit.*; -import com.sk89q.worldedit.bags.BlockBag; +import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Polygonal2DRegion; import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.RegionSelector; import com.sk89q.worldedit.spout.selections.CuboidSelection; import com.sk89q.worldedit.spout.selections.Polygonal2DSelection; import com.sk89q.worldedit.spout.selections.Selection; diff --git a/src/spout/java/com/sk89q/worldedit/spout/selections/CuboidSelection.java b/src/spout/java/com/sk89q/worldedit/spout/selections/CuboidSelection.java index 299210bc3..c13aba856 100644 --- a/src/spout/java/com/sk89q/worldedit/spout/selections/CuboidSelection.java +++ b/src/spout/java/com/sk89q/worldedit/spout/selections/CuboidSelection.java @@ -24,8 +24,8 @@ package com.sk89q.worldedit.spout.selections; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.spout.SpoutUtil; import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.regions.CuboidRegionSelector; -import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; +import com.sk89q.worldedit.regions.selector.RegionSelector; import org.spout.api.geo.World; import org.spout.api.geo.discrete.Point; diff --git a/src/spout/java/com/sk89q/worldedit/spout/selections/Polygonal2DSelection.java b/src/spout/java/com/sk89q/worldedit/spout/selections/Polygonal2DSelection.java index 9ebd8a0f9..6bc1045b4 100644 --- a/src/spout/java/com/sk89q/worldedit/spout/selections/Polygonal2DSelection.java +++ b/src/spout/java/com/sk89q/worldedit/spout/selections/Polygonal2DSelection.java @@ -24,8 +24,8 @@ package com.sk89q.worldedit.spout.selections; import com.sk89q.worldedit.BlockVector2D; import com.sk89q.worldedit.LocalWorld; import com.sk89q.worldedit.regions.Polygonal2DRegion; -import com.sk89q.worldedit.regions.Polygonal2DRegionSelector; -import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.Polygonal2DRegionSelector; +import com.sk89q.worldedit.regions.selector.RegionSelector; import com.sk89q.worldedit.spout.SpoutUtil; import org.spout.api.geo.World; diff --git a/src/spout/java/com/sk89q/worldedit/spout/selections/RegionSelection.java b/src/spout/java/com/sk89q/worldedit/spout/selections/RegionSelection.java index 8b49063f2..38c810c8b 100644 --- a/src/spout/java/com/sk89q/worldedit/spout/selections/RegionSelection.java +++ b/src/spout/java/com/sk89q/worldedit/spout/selections/RegionSelection.java @@ -23,7 +23,7 @@ package com.sk89q.worldedit.spout.selections; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.RegionSelector; import com.sk89q.worldedit.spout.SpoutUtil; import org.spout.api.geo.World; import org.spout.api.geo.discrete.Point; diff --git a/src/spout/java/com/sk89q/worldedit/spout/selections/Selection.java b/src/spout/java/com/sk89q/worldedit/spout/selections/Selection.java index 5f83c5712..cf3a054e0 100644 --- a/src/spout/java/com/sk89q/worldedit/spout/selections/Selection.java +++ b/src/spout/java/com/sk89q/worldedit/spout/selections/Selection.java @@ -22,7 +22,7 @@ package com.sk89q.worldedit.spout.selections; import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.RegionSelector; import org.spout.api.geo.World; import org.spout.api.geo.discrete.Point; diff --git a/src/test/java/com/sk89q/worldedit/expression/ExpressionTest.java b/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java similarity index 93% rename from src/test/java/com/sk89q/worldedit/expression/ExpressionTest.java rename to src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java index ab30d0b27..9117f0688 100644 --- a/src/test/java/com/sk89q/worldedit/expression/ExpressionTest.java +++ b/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java @@ -1,188 +1,188 @@ -package com.sk89q.worldedit.expression; - -import static org.junit.Assert.*; -import static java.lang.Math.*; - -import com.sk89q.worldedit.expression.runtime.ExpressionEnvironment; -import org.junit.*; - -import com.sk89q.worldedit.expression.lexer.LexerException; -import com.sk89q.worldedit.expression.parser.ParserException; -import com.sk89q.worldedit.expression.runtime.EvaluationException; - -public class ExpressionTest { - @Test - public void testEvaluate() throws ExpressionException { - // check - assertEquals(1 - 2 + 3, simpleEval("1 - 2 + 3"), 0); - - // check unary ops - assertEquals(2 + +4, simpleEval("2 + +4"), 0); - assertEquals(2 - -4, simpleEval("2 - -4"), 0); - assertEquals(2 * -4, simpleEval("2 * -4"), 0); - - // check functions - assertEquals(sin(5), simpleEval("sin(5)"), 0); - assertEquals(atan2(3, 4), simpleEval("atan2(3, 4)"), 0); - - // check variables - assertEquals(8, compile("foo+bar", "foo", "bar").evaluate(5, 3), 0); - } - - @Test - public void testErrors() throws ExpressionException { - // test lexer errors - try { - compile("#"); - fail("Error expected"); - } catch (LexerException e) { - assertEquals("Error position", 0, e.getPosition()); - } - - // test parser errors - try { - compile("x"); - fail("Error expected"); - } catch (ParserException e) { - assertEquals("Error position", 0, e.getPosition()); - } - try { - compile("x()"); - fail("Error expected"); - } catch (ParserException e) { - assertEquals("Error position", 0, e.getPosition()); - } - try { - compile("("); - fail("Error expected"); - } catch (ParserException e) {} - try { - compile("x("); - fail("Error expected"); - } catch (ParserException e) {} - - // test overloader errors - try { - compile("atan2(1)"); - fail("Error expected"); - } catch (ParserException e) { - assertEquals("Error position", 0, e.getPosition()); - } - try { - compile("atan2(1, 2, 3)"); - fail("Error expected"); - } catch (ParserException e) { - assertEquals("Error position", 0, e.getPosition()); - } - try { - compile("rotate(1, 2, 3)"); - fail("Error expected"); - } catch (ParserException e) { - assertEquals("Error position", 0, e.getPosition()); - } - } - - @Test - public void testAssign() throws ExpressionException { - Expression foo = compile("{a=x} b=y; c=z", "x", "y", "z", "a", "b", "c"); - foo.evaluate(2, 3, 5); - assertEquals(2, foo.getVariable("a", false).getValue(), 0); - assertEquals(3, foo.getVariable("b", false).getValue(), 0); - assertEquals(5, foo.getVariable("c", false).getValue(), 0); - } - - @Test - public void testIf() throws ExpressionException { - assertEquals(40, simpleEval("if (1) x=4; else y=5; x*10+y;"), 0); - assertEquals(5, simpleEval("if (0) x=4; else y=5; x*10+y;"), 0); - - // test 'dangling else' - final Expression expression1 = compile("if (1) if (0) x=4; else y=5;", "x", "y"); - expression1.evaluate(1, 2); - assertEquals(1, expression1.getVariable("x", false).getValue(), 0); - assertEquals(5, expression1.getVariable("y", false).getValue(), 0); - - // test if the if construct is correctly recognized as a statement - final Expression expression2 = compile("if (0) if (1) x=5; y=4;", "x", "y"); - expression2.evaluate(1, 2); - assertEquals(4, expression2.getVariable("y", false).getValue(), 0); - } - - @Test - public void testWhile() throws ExpressionException { - assertEquals(5, simpleEval("c=5; a=0; while (c > 0) { ++a; --c; } a"), 0); - assertEquals(5, simpleEval("c=5; a=0; do { ++a; --c; } while (c > 0); a"), 0); - } - - @Test - public void testFor() throws ExpressionException { - assertEquals(5, simpleEval("a=0; for (i=0; i<5; ++i) { ++a; } a"), 0); - assertEquals(12345, simpleEval("y=0; for (i=1,5) { y *= 10; y += i; } y"), 0); - } - - @Test - public void testSwitch() throws ExpressionException { - assertEquals(523, simpleEval("x=1;y=2;z=3;switch (1) { case 1: x=5; break; case 2: y=6; break; default: z=7 } x*100+y*10+z"), 0); - assertEquals(163, simpleEval("x=1;y=2;z=3;switch (2) { case 1: x=5; break; case 2: y=6; break; default: z=7 } x*100+y*10+z"), 0); - assertEquals(127, simpleEval("x=1;y=2;z=3;switch (3) { case 1: x=5; break; case 2: y=6; break; default: z=7 } x*100+y*10+z"), 0); - - assertEquals(567, simpleEval("x=1;y=2;z=3;switch (1) { case 1: x=5; case 2: y=6; default: z=7 } x*100+y*10+z"), 0); - assertEquals(167, simpleEval("x=1;y=2;z=3;switch (2) { case 1: x=5; case 2: y=6; default: z=7 } x*100+y*10+z"), 0); - assertEquals(127, simpleEval("x=1;y=2;z=3;switch (3) { case 1: x=5; case 2: y=6; default: z=7 } x*100+y*10+z"), 0); - } - - @Test - public void testQuery() throws Exception { - assertEquals(1, simpleEval("a=1;b=2;query(3,4,5,a,b); a==3 && b==4"), 0); - assertEquals(1, simpleEval("a=1;b=2;queryAbs(3,4,5,a*1,b*1); a==1 && b==2"), 0); - assertEquals(1, simpleEval("a=1;b=2;queryRel(3,4,5,(a),(b)); a==300 && b==400"), 0); - assertEquals(1, simpleEval("query(3,4,5,3,4)"), 0); - assertEquals(1, simpleEval("!query(3,4,5,3,2)"), 0); - assertEquals(1, simpleEval("!queryAbs(3,4,5,10,40)"), 0); - assertEquals(1, simpleEval("!queryRel(3,4,5,100,200)"), 0); - } - - private double simpleEval(String expressionString) throws ExpressionException { - final Expression expression = compile(expressionString); - - expression.setEnvironment(new ExpressionEnvironment() { - @Override - public int getBlockType(double x, double y, double z) { - return (int) x; - } - - @Override - public int getBlockData(double x, double y, double z) { - return (int) y; - } - - @Override - public int getBlockTypeAbs(double x, double y, double z) { - return (int) x*10; - } - - @Override - public int getBlockDataAbs(double x, double y, double z) { - return (int) y*10; - } - - @Override - public int getBlockTypeRel(double x, double y, double z) { - return (int) x*100; - } - - @Override - public int getBlockDataRel(double x, double y, double z) { - return (int) y*100; - } - }); - - return expression.evaluate(); - } - - private Expression compile(String expressionString, String... variableNames) throws ExpressionException, EvaluationException { - final Expression expression = Expression.compile(expressionString, variableNames); - expression.optimize(); - return expression; - } -} +package com.sk89q.worldedit.internal.expression; + +import static org.junit.Assert.*; +import static java.lang.Math.*; + +import com.sk89q.worldedit.internal.expression.runtime.ExpressionEnvironment; +import org.junit.*; + +import com.sk89q.worldedit.internal.expression.lexer.LexerException; +import com.sk89q.worldedit.internal.expression.parser.ParserException; +import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; + +public class ExpressionTest { + @Test + public void testEvaluate() throws ExpressionException { + // check + assertEquals(1 - 2 + 3, simpleEval("1 - 2 + 3"), 0); + + // check unary ops + assertEquals(2 + +4, simpleEval("2 + +4"), 0); + assertEquals(2 - -4, simpleEval("2 - -4"), 0); + assertEquals(2 * -4, simpleEval("2 * -4"), 0); + + // check functions + assertEquals(sin(5), simpleEval("sin(5)"), 0); + assertEquals(atan2(3, 4), simpleEval("atan2(3, 4)"), 0); + + // check variables + assertEquals(8, compile("foo+bar", "foo", "bar").evaluate(5, 3), 0); + } + + @Test + public void testErrors() throws ExpressionException { + // test lexer errors + try { + compile("#"); + fail("Error expected"); + } catch (LexerException e) { + assertEquals("Error position", 0, e.getPosition()); + } + + // test parser errors + try { + compile("x"); + fail("Error expected"); + } catch (ParserException e) { + assertEquals("Error position", 0, e.getPosition()); + } + try { + compile("x()"); + fail("Error expected"); + } catch (ParserException e) { + assertEquals("Error position", 0, e.getPosition()); + } + try { + compile("("); + fail("Error expected"); + } catch (ParserException e) {} + try { + compile("x("); + fail("Error expected"); + } catch (ParserException e) {} + + // test overloader errors + try { + compile("atan2(1)"); + fail("Error expected"); + } catch (ParserException e) { + assertEquals("Error position", 0, e.getPosition()); + } + try { + compile("atan2(1, 2, 3)"); + fail("Error expected"); + } catch (ParserException e) { + assertEquals("Error position", 0, e.getPosition()); + } + try { + compile("rotate(1, 2, 3)"); + fail("Error expected"); + } catch (ParserException e) { + assertEquals("Error position", 0, e.getPosition()); + } + } + + @Test + public void testAssign() throws ExpressionException { + Expression foo = compile("{a=x} b=y; c=z", "x", "y", "z", "a", "b", "c"); + foo.evaluate(2, 3, 5); + assertEquals(2, foo.getVariable("a", false).getValue(), 0); + assertEquals(3, foo.getVariable("b", false).getValue(), 0); + assertEquals(5, foo.getVariable("c", false).getValue(), 0); + } + + @Test + public void testIf() throws ExpressionException { + assertEquals(40, simpleEval("if (1) x=4; else y=5; x*10+y;"), 0); + assertEquals(5, simpleEval("if (0) x=4; else y=5; x*10+y;"), 0); + + // test 'dangling else' + final Expression expression1 = compile("if (1) if (0) x=4; else y=5;", "x", "y"); + expression1.evaluate(1, 2); + assertEquals(1, expression1.getVariable("x", false).getValue(), 0); + assertEquals(5, expression1.getVariable("y", false).getValue(), 0); + + // test if the if construct is correctly recognized as a statement + final Expression expression2 = compile("if (0) if (1) x=5; y=4;", "x", "y"); + expression2.evaluate(1, 2); + assertEquals(4, expression2.getVariable("y", false).getValue(), 0); + } + + @Test + public void testWhile() throws ExpressionException { + assertEquals(5, simpleEval("c=5; a=0; while (c > 0) { ++a; --c; } a"), 0); + assertEquals(5, simpleEval("c=5; a=0; do { ++a; --c; } while (c > 0); a"), 0); + } + + @Test + public void testFor() throws ExpressionException { + assertEquals(5, simpleEval("a=0; for (i=0; i<5; ++i) { ++a; } a"), 0); + assertEquals(12345, simpleEval("y=0; for (i=1,5) { y *= 10; y += i; } y"), 0); + } + + @Test + public void testSwitch() throws ExpressionException { + assertEquals(523, simpleEval("x=1;y=2;z=3;switch (1) { case 1: x=5; break; case 2: y=6; break; default: z=7 } x*100+y*10+z"), 0); + assertEquals(163, simpleEval("x=1;y=2;z=3;switch (2) { case 1: x=5; break; case 2: y=6; break; default: z=7 } x*100+y*10+z"), 0); + assertEquals(127, simpleEval("x=1;y=2;z=3;switch (3) { case 1: x=5; break; case 2: y=6; break; default: z=7 } x*100+y*10+z"), 0); + + assertEquals(567, simpleEval("x=1;y=2;z=3;switch (1) { case 1: x=5; case 2: y=6; default: z=7 } x*100+y*10+z"), 0); + assertEquals(167, simpleEval("x=1;y=2;z=3;switch (2) { case 1: x=5; case 2: y=6; default: z=7 } x*100+y*10+z"), 0); + assertEquals(127, simpleEval("x=1;y=2;z=3;switch (3) { case 1: x=5; case 2: y=6; default: z=7 } x*100+y*10+z"), 0); + } + + @Test + public void testQuery() throws Exception { + assertEquals(1, simpleEval("a=1;b=2;query(3,4,5,a,b); a==3 && b==4"), 0); + assertEquals(1, simpleEval("a=1;b=2;queryAbs(3,4,5,a*1,b*1); a==1 && b==2"), 0); + assertEquals(1, simpleEval("a=1;b=2;queryRel(3,4,5,(a),(b)); a==300 && b==400"), 0); + assertEquals(1, simpleEval("query(3,4,5,3,4)"), 0); + assertEquals(1, simpleEval("!query(3,4,5,3,2)"), 0); + assertEquals(1, simpleEval("!queryAbs(3,4,5,10,40)"), 0); + assertEquals(1, simpleEval("!queryRel(3,4,5,100,200)"), 0); + } + + private double simpleEval(String expressionString) throws ExpressionException { + final Expression expression = compile(expressionString); + + expression.setEnvironment(new ExpressionEnvironment() { + @Override + public int getBlockType(double x, double y, double z) { + return (int) x; + } + + @Override + public int getBlockData(double x, double y, double z) { + return (int) y; + } + + @Override + public int getBlockTypeAbs(double x, double y, double z) { + return (int) x*10; + } + + @Override + public int getBlockDataAbs(double x, double y, double z) { + return (int) y*10; + } + + @Override + public int getBlockTypeRel(double x, double y, double z) { + return (int) x*100; + } + + @Override + public int getBlockDataRel(double x, double y, double z) { + return (int) y*100; + } + }); + + return expression.evaluate(); + } + + private Expression compile(String expressionString, String... variableNames) throws ExpressionException, EvaluationException { + final Expression expression = Expression.compile(expressionString, variableNames); + expression.optimize(); + return expression; + } +}