diff --git a/favs/src/main/java/com/thevoxelbox/voxelsniper/RangeBlockHelper.java b/favs/src/main/java/com/thevoxelbox/voxelsniper/RangeBlockHelper.java index 26778a69c..ad5bea3e0 100644 --- a/favs/src/main/java/com/thevoxelbox/voxelsniper/RangeBlockHelper.java +++ b/favs/src/main/java/com/thevoxelbox/voxelsniper/RangeBlockHelper.java @@ -211,46 +211,6 @@ public class RangeBlockHelper { return this.getCurBlock(); } - public final void setCurBlock(int type) { - if(this.getCurBlock() != null) { - this.world.getBlockAt(this.targetX, this.targetY, this.targetZ).setType(getType(type)); - } - - } - - public final void setFaceBlock(int type) { - while(this.getNextBlock() != null && isAir(this.getCurBlock().getType())) { - ; - } - - if(this.getCurBlock() != null) { - this.world.getBlockAt(this.targetX, this.targetY, this.targetZ).setType(getType(type)); - } - - } - - private Material getType(int id) { - return BukkitAdapter.adapt(LegacyMapper.getInstance().getBlockFromLegacy(id).getBlockType()); - } - - public final void setLastBlock(int type) { - if(this.getLastBlock() != null) { - this.world.getBlockAt(this.lastX, this.lastY, this.lastZ).setType(getType(type)); - } - - } - - public final void setTargetBlock(int type) { - while(this.getNextBlock() != null && isAir(this.getCurBlock().getType())) { - ; - } - - if(this.getCurBlock() != null) { - this.world.getBlockAt(this.targetX, this.targetY, this.targetZ).setType(getType(type)); - } - - } - private AsyncBlock getRange() { this.lastX = this.targetX; this.lastY = this.targetY; diff --git a/favs/src/main/java/com/thevoxelbox/voxelsniper/brush/BlockResetBrush.java b/favs/src/main/java/com/thevoxelbox/voxelsniper/brush/BlockResetBrush.java index f2383e69c..538212094 100644 --- a/favs/src/main/java/com/thevoxelbox/voxelsniper/brush/BlockResetBrush.java +++ b/favs/src/main/java/com/thevoxelbox/voxelsniper/brush/BlockResetBrush.java @@ -1,5 +1,6 @@ package com.thevoxelbox.voxelsniper.brush; +import com.sk89q.worldedit.world.block.BlockID; import com.thevoxelbox.voxelsniper.Message; import com.thevoxelbox.voxelsniper.SnipeData; import org.bukkit.Material; @@ -11,8 +12,18 @@ public class BlockResetBrush extends Brush { private static final ArrayList DENIED_UPDATES = new ArrayList<>(); static { - BlockResetBrush.DENIED_UPDATES.add(Material.SIGN); - BlockResetBrush.DENIED_UPDATES.add(Material.WALL_SIGN); + BlockResetBrush.DENIED_UPDATES.add(Material.ACACIA_SIGN); + BlockResetBrush.DENIED_UPDATES.add(Material.SPRUCE_SIGN); + BlockResetBrush.DENIED_UPDATES.add(Material.ACACIA_WALL_SIGN); + BlockResetBrush.DENIED_UPDATES.add(Material.BIRCH_SIGN); + BlockResetBrush.DENIED_UPDATES.add(Material.SPRUCE_WALL_SIGN); + BlockResetBrush.DENIED_UPDATES.add(Material.BIRCH_WALL_SIGN); + BlockResetBrush.DENIED_UPDATES.add(Material.DARK_OAK_SIGN); + BlockResetBrush.DENIED_UPDATES.add(Material.DARK_OAK_WALL_SIGN); + BlockResetBrush.DENIED_UPDATES.add(Material.JUNGLE_SIGN); + BlockResetBrush.DENIED_UPDATES.add(Material.JUNGLE_WALL_SIGN); + BlockResetBrush.DENIED_UPDATES.add(Material.OAK_SIGN); + BlockResetBrush.DENIED_UPDATES.add(Material.OAK_WALL_SIGN); BlockResetBrush.DENIED_UPDATES.add(Material.CHEST); BlockResetBrush.DENIED_UPDATES.add(Material.FURNACE); BlockResetBrush.DENIED_UPDATES.add(Material.REDSTONE_TORCH); diff --git a/favs/src/main/java/com/thevoxelbox/voxelsniper/util/VoxelList.java b/favs/src/main/java/com/thevoxelbox/voxelsniper/util/VoxelList.java index a5874f10e..a360d5a0a 100644 --- a/favs/src/main/java/com/thevoxelbox/voxelsniper/util/VoxelList.java +++ b/favs/src/main/java/com/thevoxelbox/voxelsniper/util/VoxelList.java @@ -11,7 +11,7 @@ import org.bukkit.block.data.BlockData; */ public class VoxelList { - private BlockMask mask = new BlockMask(); + private BlockMask mask = new BlockMask(new NullExtent()); /** * Adds the specified id, data value pair to the VoxelList. A data value of -1 will operate on all data values of that id. @@ -19,7 +19,7 @@ public class VoxelList { * @param i */ public void add(BlockState i) { - this.mask = mask.toBuilder().add(i).build(NullExtent.INSTANCE); + this.mask = mask.add(i); } public void add(BlockMask mask) { @@ -32,7 +32,7 @@ public class VoxelList { * @return true if this list contained the specified element */ public boolean removeValue(final BlockState state) { - this.mask = mask.toBuilder().remove(state).build(NullExtent.INSTANCE); + this.mask = mask.remove(state); return true; } @@ -53,7 +53,7 @@ public class VoxelList { * Clears the VoxelList. */ public void clear() { - mask = mask.toBuilder().clear().build(NullExtent.INSTANCE); + mask = mask.clear(); } /** @@ -62,7 +62,7 @@ public class VoxelList { * @return true if this list contains no elements */ public boolean isEmpty() { - return mask.toBuilder().isEmpty(); + return mask.isEmpty(); } /** diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/BStats.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/BStats.java deleted file mode 100644 index 8031c1242..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/BStats.java +++ /dev/null @@ -1,705 +0,0 @@ -package com.boydti.fawe.bukkit; - -import com.boydti.fawe.Fawe; -import org.bstats.bukkit.Metrics; -import org.bukkit.Bukkit; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.RegisteredServiceProvider; -import org.bukkit.plugin.ServicePriority; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; - -import javax.net.ssl.HttpsURLConnection; -import java.io.*; -import java.lang.reflect.InvocationTargetException; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.Callable; -import java.util.logging.Level; -import java.util.zip.GZIPOutputStream; - -/** - * bStats collects some data for plugin authors. - *

- * Check out https://bStats.org/ to learn more about bStats! - */ -@SuppressWarnings({"WeakerAccess", "unused"}) public class BStats { - - static { - // You can use the property to disable the check in your test environment - if (System.getProperty("bstats.relocatecheck") == null || !System - .getProperty("bstats.relocatecheck").equals("false")) { - // Maven's Relocate is clever and changes strings, too. So we have to use this little "trick" ... :D - final String defaultPackage = new String( - new byte[] {'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'k', - 'k', 'i', 't'}); - final String examplePackage = - new String(new byte[] {'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'}); - // We want to make sure nobody just copy & pastes the example and use the wrong package names - if (Metrics.class.getPackage().getName().equals(defaultPackage) || Metrics.class - .getPackage().getName().equals(examplePackage)) { - throw new IllegalStateException( - "bStats Metrics class has not been relocated correctly!"); - } - } - } - - // The version of this bStats class - public static final int B_STATS_VERSION = 1; - - // The url to which the data is sent - private static final String URL = "https://bStats.org/submitData/bukkit"; - - // Is bStats enabled on this server? - private boolean enabled; - - // Should failed requests be logged? - private static boolean logFailedRequests; - - // Should the sent data be logged? - private static boolean logSentData; - - // Should the response text be logged? - private static boolean logResponseStatusText; - - // The uuid of the server - private static String serverUUID; - - // The plugin - private final Plugin plugin; - - // A list with all custom charts - private final List charts = new ArrayList<>(); - - /** - * Class constructor. - * - * @param plugin The plugin which stats should be submitted. - */ - public BStats(Plugin plugin) { - if (plugin == null) { - throw new IllegalArgumentException("Plugin cannot be null!"); - } - this.plugin = plugin; - - // Get the config file - File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); - File configFile = new File(bStatsFolder, "config.yml"); - YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); - - // Check if the config file exists - if (!config.isSet("serverUuid")) { - - // Add default values - config.addDefault("enabled", true); - // Every server gets it's unique random id. - config.addDefault("serverUuid", UUID.randomUUID().toString()); - // Should failed request be logged? - config.addDefault("logFailedRequests", false); - // Should the sent data be logged? - config.addDefault("logSentData", false); - // Should the response text be logged? - config.addDefault("logResponseStatusText", false); - - // Inform the server owners about bStats - config.options().header( - "bStats collects some data for plugin authors like how many servers are using their plugins.\n" - + "To honor their work, you should not disable it.\n" - + "This has nearly no effect on the server performance!\n" - + "Check out https://bStats.org/ to learn more :)").copyDefaults(true); - try { - config.save(configFile); - } catch (IOException ignored) { - } - } - - // Load the data - enabled = config.getBoolean("enabled", true); - serverUUID = config.getString("serverUuid"); - logFailedRequests = config.getBoolean("logFailedRequests", false); - logSentData = config.getBoolean("logSentData", false); - logResponseStatusText = config.getBoolean("logResponseStatusText", false); - - if (enabled) { - boolean found = false; - // Search for all other bStats Metrics classes to see if we are the first one - for (Class service : Bukkit.getServicesManager().getKnownServices()) { - try { - service.getField("B_STATS_VERSION"); // Our identifier :) - found = true; // We aren't the first - break; - } catch (NoSuchFieldException ignored) { - } - } - // Register our service - Bukkit.getServicesManager() - .register(BStats.class, this, plugin, ServicePriority.Normal); - if (!found) { - // We are the first! - startSubmitting(); - } - } - } - - /** - * Checks if bStats is enabled. - * - * @return Whether bStats is enabled or not. - */ - public boolean isEnabled() { - return enabled; - } - - /** - * Adds a custom chart. - * - * @param chart The chart to add. - */ - public void addCustomChart(CustomChart chart) { - if (chart == null) { - throw new IllegalArgumentException("Chart cannot be null!"); - } - charts.add(chart); - } - - /** - * Starts the Scheduler which submits our data every 30 minutes. - */ - private void startSubmitting() { - final Timer timer = - new Timer(true); // We use a timer cause the Bukkit scheduler is affected by server lags - timer.scheduleAtFixedRate(new TimerTask() { - @Override public void run() { - if (!plugin.isEnabled()) { // Plugin was disabled - timer.cancel(); - return; - } - // Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler - // Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;) - Bukkit.getScheduler().runTask(plugin, () -> submitData()); - } - }, 1000 * 60 * 5, 1000 * 60 * 30); - // Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start - // WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted! - // WARNING: Just don't do it! - } - - /** - * Gets the plugin specific data. - * This method is called using Reflection. - * - * @return The plugin specific data. - */ - public JSONObject getPluginData() { - JSONObject data = new JSONObject(); - - String pluginName = "FastAsyncWorldEdit"; - String pluginVersion = Fawe.get().getVersion() + ""; - - data.put("pluginName", pluginName); // Append the name of the plugin - data.put("pluginVersion", pluginVersion); // Append the version of the plugin - JSONArray customCharts = new JSONArray(); - for (CustomChart customChart : charts) { - // Add the data of the custom charts - JSONObject chart = customChart.getRequestJsonObject(); - if (chart == null) { // If the chart is null, we skip it - continue; - } - customCharts.add(chart); - } - data.put("customCharts", customCharts); - - return data; - } - - /** - * Gets the server specific data. - * - * @return The server specific data. - */ - private JSONObject getServerData() { - // Minecraft specific data - int playerAmount = getPlayerCount(); - int onlineMode = Fawe.imp().isOnlineMode() ? 1 : 0; - String serverVersion = Fawe.imp().getPlatformVersion(); - - // OS/Java specific data - String javaVersion = System.getProperty("java.version"); - String osName = System.getProperty("os.name"); - String osArch = System.getProperty("os.arch"); - String osVersion = System.getProperty("os.version"); - int coreCount = Runtime.getRuntime().availableProcessors(); - - JSONObject data = new JSONObject(); - - data.put("serverUUID", serverUUID); - - data.put("playerAmount", playerAmount); - data.put("onlineMode", onlineMode); - data.put("bukkitVersion", serverVersion); - - data.put("javaVersion", javaVersion); - data.put("osName", osName); - data.put("osArch", osArch); - data.put("osVersion", osVersion); - data.put("coreCount", coreCount); - - return data; - } - - public int getPlayerCount() { - return Fawe.imp() == null ? 1 : Fawe.imp().getPlayerCount(); - } - - /** - * Collects the data and sends it afterwards. - */ - private void submitData() { - final JSONObject data = getServerData(); - - JSONArray pluginData = new JSONArray(); - // Search for all other bStats Metrics classes to get their plugin data - for (Class service : Bukkit.getServicesManager().getKnownServices()) { - try { - service.getField("B_STATS_VERSION"); // Our identifier :) - - for (RegisteredServiceProvider provider : Bukkit.getServicesManager() - .getRegistrations(service)) { - try { - pluginData.add(provider.getService().getMethod("getPluginData") - .invoke(provider.getProvider())); - } catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { - } - } - } catch (NoSuchFieldException ignored) { - } - } - - data.put("plugins", pluginData); - - // Create a new thread for the connection to the bStats server - new Thread(() -> { - try { - // Send the data - sendData(plugin, data); - } catch (Exception e) { - // Something went wrong! :( - if (logFailedRequests) { - plugin.getLogger() - .log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), - e); - } - } - }).start(); - } - - /** - * Sends the data to the bStats server. - * - * @param plugin Any plugin. It's just used to get a logger instance. - * @param data The data to send. - * @throws Exception If the request failed. - */ - private static void sendData(Plugin plugin, JSONObject data) throws Exception { - if (data == null) { - throw new IllegalArgumentException("Data cannot be null!"); - } - if (Bukkit.isPrimaryThread()) { - throw new IllegalAccessException( - "This method must not be called from the main thread!"); - } - if (logSentData) { - plugin.getLogger().info("Sending data to bStats: " + data.toString()); - } - HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection(); - - // Compress the data to save bandwidth - byte[] compressedData = compress(data.toString()); - - // Add headers - connection.setRequestMethod("POST"); - connection.addRequestProperty("Accept", "application/json"); - connection.addRequestProperty("Connection", "close"); - connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request - connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); - connection.setRequestProperty("Content-Type", - "application/json"); // We send our data in JSON format - connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION); - - // Send data - connection.setDoOutput(true); - try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) { - outputStream.write(compressedData); - outputStream.flush(); - } - - StringBuilder builder; - try (InputStream inputStream = connection.getInputStream(); - BufferedReader bufferedReader = new BufferedReader( - new InputStreamReader(inputStream))) { - - builder = new StringBuilder(); - String line; - while ((line = bufferedReader.readLine()) != null) { - builder.append(line); - } - } - if (logResponseStatusText) { - plugin.getLogger() - .info("Sent data to bStats and received response: " + builder.toString()); - } - } - - /** - * Gzips the given String. - * - * @param str The string to gzip. - * @return The gzipped String. - * @throws IOException If the compression failed. - */ - private static byte[] compress(final String str) throws IOException { - if (str == null) { - return null; - } - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - GZIPOutputStream gzip = new GZIPOutputStream(outputStream); - gzip.write(str.getBytes(StandardCharsets.UTF_8)); - gzip.close(); - return outputStream.toByteArray(); - } - - /** - * Represents a custom chart. - */ - public static abstract class CustomChart { - - // The id of the chart - final String chartId; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - */ - CustomChart(String chartId) { - if (chartId == null || chartId.isEmpty()) { - throw new IllegalArgumentException("ChartId cannot be null or empty!"); - } - this.chartId = chartId; - } - - private JSONObject getRequestJsonObject() { - JSONObject chart = new JSONObject(); - chart.put("chartId", chartId); - try { - JSONObject data = getChartData(); - if (data == null) { - // If the data is null we don't send the chart. - return null; - } - chart.put("data", data); - } catch (Throwable t) { - if (logFailedRequests) { - Bukkit.getLogger().log(Level.WARNING, - "Failed to get data for custom chart with id " + chartId, t); - } - return null; - } - return chart; - } - - protected abstract JSONObject getChartData() throws Exception; - - } - - - /** - * Represents a custom simple pie. - */ - public static class SimplePie extends CustomChart { - - private final Callable callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SimplePie(String chartId, Callable callable) { - super(chartId); - this.callable = callable; - } - - @Override protected JSONObject getChartData() throws Exception { - JSONObject data = new JSONObject(); - String value = callable.call(); - if (value == null || value.isEmpty()) { - // Null = skip the chart - return null; - } - data.put("value", value); - return data; - } - } - - - /** - * Represents a custom advanced pie. - */ - public static class AdvancedPie extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public AdvancedPie(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override protected JSONObject getChartData() throws Exception { - JSONObject data = new JSONObject(); - JSONObject values = new JSONObject(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue() == 0) { - continue; // Skip this invalid - } - allSkipped = false; - values.put(entry.getKey(), entry.getValue()); - } - if (allSkipped) { - // Null = skip the chart - return null; - } - data.put("values", values); - return data; - } - } - - - /** - * Represents a custom drilldown pie. - */ - public static class DrilldownPie extends CustomChart { - - private final Callable>> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public DrilldownPie(String chartId, Callable>> callable) { - super(chartId); - this.callable = callable; - } - - @Override public JSONObject getChartData() throws Exception { - JSONObject data = new JSONObject(); - JSONObject values = new JSONObject(); - Map> map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean reallyAllSkipped = true; - for (Map.Entry> entryValues : map.entrySet()) { - JSONObject value = new JSONObject(); - boolean allSkipped = true; - for (Map.Entry valueEntry : map.get(entryValues.getKey()) - .entrySet()) { - value.put(valueEntry.getKey(), valueEntry.getValue()); - allSkipped = false; - } - if (!allSkipped) { - reallyAllSkipped = false; - values.put(entryValues.getKey(), value); - } - } - if (reallyAllSkipped) { - // Null = skip the chart - return null; - } - data.put("values", values); - return data; - } - } - - - /** - * Represents a custom single line chart. - */ - public static class SingleLineChart extends CustomChart { - - private final Callable callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SingleLineChart(String chartId, Callable callable) { - super(chartId); - this.callable = callable; - } - - @Override protected JSONObject getChartData() throws Exception { - JSONObject data = new JSONObject(); - int value = callable.call(); - if (value == 0) { - // Null = skip the chart - return null; - } - data.put("value", value); - return data; - } - - } - - - /** - * Represents a custom multi line chart. - */ - public static class MultiLineChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public MultiLineChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override protected JSONObject getChartData() throws Exception { - JSONObject data = new JSONObject(); - JSONObject values = new JSONObject(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue() == 0) { - continue; // Skip this invalid - } - allSkipped = false; - values.put(entry.getKey(), entry.getValue()); - } - if (allSkipped) { - // Null = skip the chart - return null; - } - data.put("values", values); - return data; - } - - } - - - /** - * Represents a custom simple bar chart. - */ - public static class SimpleBarChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SimpleBarChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override protected JSONObject getChartData() throws Exception { - JSONObject data = new JSONObject(); - JSONObject values = new JSONObject(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - for (Map.Entry entry : map.entrySet()) { - JSONArray categoryValues = new JSONArray(); - categoryValues.add(entry.getValue()); - values.put(entry.getKey(), categoryValues); - } - data.put("values", values); - return data; - } - - } - - - /** - * Represents a custom advanced bar chart. - */ - public static class AdvancedBarChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public AdvancedBarChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override protected JSONObject getChartData() throws Exception { - JSONObject data = new JSONObject(); - JSONObject values = new JSONObject(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue().length == 0) { - continue; // Skip this invalid - } - allSkipped = false; - JSONArray categoryValues = new JSONArray(); - for (int categoryValue : entry.getValue()) { - categoryValues.add(categoryValue); - } - values.put(entry.getKey(), categoryValues); - } - if (allSkipped) { - // Null = skip the chart - return null; - } - data.put("values", values); - return data; - } - } - -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java index 0f3846a80..435366446 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java @@ -2,9 +2,13 @@ package com.boydti.fawe.bukkit; import com.boydti.fawe.Fawe; import com.boydti.fawe.IFawe; +import com.boydti.fawe.beta.implementation.QueueHandler; +import com.boydti.fawe.bukkit.beta.BukkitQueue; +import com.boydti.fawe.bukkit.beta.BukkitQueueHandler; import com.boydti.fawe.bukkit.chat.BukkitChatManager; import com.boydti.fawe.bukkit.listener.BrushListener; import com.boydti.fawe.bukkit.listener.BukkitImageListener; +import com.boydti.fawe.bukkit.listener.CFIPacketListener; import com.boydti.fawe.bukkit.listener.RenderListener; import com.boydti.fawe.bukkit.regions.*; import com.boydti.fawe.bukkit.util.BukkitReflectionUtils; @@ -17,6 +21,7 @@ import com.boydti.fawe.bukkit.v0.BukkitQueue_All; import com.boydti.fawe.bukkit.v0.ChunkListener_8; import com.boydti.fawe.bukkit.v0.ChunkListener_9; import com.boydti.fawe.bukkit.v1_13.BukkitQueue_1_13; +import com.boydti.fawe.bukkit.v1_14.BukkitQueue_1_14; import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.FaweCommand; @@ -29,7 +34,9 @@ import com.boydti.fawe.util.TaskManager; import com.boydti.fawe.util.image.ImageViewer; import com.sk89q.worldedit.world.World; +import org.bstats.bukkit.MetricsLite; import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.command.PluginCommand; import org.bukkit.entity.Player; @@ -37,9 +44,11 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.world.ChunkUnloadEvent; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; +import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.FileOutputStream; @@ -61,7 +70,6 @@ public class FaweBukkit implements IFawe, Listener { private BukkitImageListener imageListener; //private CFIPacketListener packetListener; - public VaultUtil getVault() { return this.vault; } @@ -118,6 +126,19 @@ public class FaweBukkit implements IFawe, Listener { }); } +// @Override // Please don't delete this again, it's WIP +// public void registerPacketListener() { +// PluginManager manager = Bukkit.getPluginManager(); +// if (packetListener == null && manager.getPlugin("ProtocolLib") != null) { +// packetListener = new CFIPacketListener(plugin); +// } +// } + + @Override + public QueueHandler getQueueHandler() { + return new BukkitQueueHandler(); + } + @Override public synchronized ImageViewer getImageViewer(FawePlayer fp) { if (listeningImages && imageListener == null) return null; @@ -219,7 +240,7 @@ public class FaweBukkit implements IFawe, Listener { } @Override public void startMetrics() { - new BStats(plugin); + new MetricsLite(plugin); } public ItemUtil getItemUtil() { @@ -529,6 +550,7 @@ public class FaweBukkit implements IFawe, Listener { } public enum Version { + v1_14_R1, v1_13_R2, NONE, } @@ -537,6 +559,8 @@ public class FaweBukkit implements IFawe, Listener { switch (getVersion()) { case v1_13_R2: return new BukkitQueue_1_13(world); + case v1_14_R1: + return new BukkitQueue_1_14(world); default: case NONE: return new BukkitQueue_All(world); @@ -547,6 +571,8 @@ public class FaweBukkit implements IFawe, Listener { switch (getVersion()) { case v1_13_R2: return new BukkitQueue_1_13(world); + case v1_14_R1: + return new BukkitQueue_1_14(world); default: case NONE: return new BukkitQueue_All(world); diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/v1_13_1/Spigot_v1_13_R2.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/v1_13_1/Spigot_v1_13_R2.java index d16684bcd..e134b532d 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/v1_13_1/Spigot_v1_13_R2.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/v1_13_1/Spigot_v1_13_R2.java @@ -64,6 +64,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.function.Supplier; @@ -102,16 +103,16 @@ public final class Spigot_v1_13_R2 extends CachedBukkitAdapter implements Bukkit nbtCreateTagMethod.setAccessible(true); } - public int[] idbToStateOrdinal; + public char[] idbToStateOrdinal; - private boolean init() { + private synchronized boolean init() { if (idbToStateOrdinal != null) return false; - idbToStateOrdinal = new int[Block.REGISTRY_ID.a()]; // size + idbToStateOrdinal = new char[Block.REGISTRY_ID.a()]; // size for (int i = 0; i < idbToStateOrdinal.length; i++) { BlockState state = BlockTypes.states[i]; BlockMaterial_1_13 material = (BlockMaterial_1_13) state.getMaterial(); int id = Block.REGISTRY_ID.getId(material.getState()); - idbToStateOrdinal[id] = state.getOrdinal(); + idbToStateOrdinal[id] = state.getOrdinalChar(); } return true; } @@ -365,7 +366,7 @@ public final class Spigot_v1_13_R2 extends CachedBukkitAdapter implements Bukkit property = new BooleanProperty(state.a(), ImmutableList.copyOf(state.d())); } else if (state instanceof BlockStateDirection) { property = new DirectionalProperty(state.a(), - (List) state.d().stream().map(e -> Direction.valueOf(((INamable) e).getName().toUpperCase())).collect(Collectors.toList())); + (List) state.d().stream().map(e -> Direction.valueOf(((INamable) e).getName().toUpperCase(Locale.ROOT))).collect(Collectors.toList())); } else if (state instanceof BlockStateEnum) { property = new EnumProperty(state.a(), (List) state.d().stream().map(e -> ((INamable) e).getName()).collect(Collectors.toList())); @@ -533,8 +534,18 @@ public final class Spigot_v1_13_R2 extends CachedBukkitAdapter implements Bukkit int id = Block.REGISTRY_ID.getId(ibd); return idbToStateOrdinal[id]; } catch (NullPointerException e) { - if (init()) return adaptToInt(ibd); - throw e; + init(); + return adaptToInt(ibd); + } + } + + public char adaptToChar(IBlockData ibd) { + try { + int id = Block.REGISTRY_ID.getId(ibd); + return idbToStateOrdinal[id]; + } catch (NullPointerException e) { + init(); + return adaptToChar(ibd); } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java new file mode 100644 index 000000000..b9767bbef --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java @@ -0,0 +1,356 @@ +package com.boydti.fawe.bukkit.beta; + +import com.boydti.fawe.Fawe; +import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.IQueueExtent; +import com.boydti.fawe.beta.IChunkSet; +import com.boydti.fawe.beta.implementation.QueueHandler; +import com.boydti.fawe.beta.implementation.holder.ChunkHolder; +import com.boydti.fawe.util.MemUtil; +import com.boydti.fawe.util.ReflectionUtils; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.LongTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.world.biome.BiomeType; +import net.minecraft.server.v1_14_R1.BiomeBase; +import net.minecraft.server.v1_14_R1.BlockPosition; +import net.minecraft.server.v1_14_R1.Chunk; +import net.minecraft.server.v1_14_R1.ChunkSection; +import net.minecraft.server.v1_14_R1.Entity; +import net.minecraft.server.v1_14_R1.EntityTypes; +import net.minecraft.server.v1_14_R1.NBTTagCompound; +import net.minecraft.server.v1_14_R1.NBTTagInt; +import net.minecraft.server.v1_14_R1.TileEntity; +import org.bukkit.World; +import org.bukkit.block.Biome; +import org.bukkit.craftbukkit.v1_14_R1.block.CraftBlock; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; + +public class BukkitChunkHolder> extends ChunkHolder { + @Override + public void init(final IQueueExtent extent, final int X, final int Z) { + super.init(extent, X, Z); + } + + @Override + public IChunkGet get() { + BukkitQueue extent = (BukkitQueue) getExtent(); + return new BukkitGetBlocks(extent.getNmsWorld(), getX(), getZ(), MemUtil.isMemoryFree()); + } + + private void updateGet(BukkitGetBlocks get, Chunk nmsChunk, ChunkSection[] sections, ChunkSection section, char[] arr, int layer) { + synchronized (get) { + if (get.nmsChunk != nmsChunk) { + get.nmsChunk = nmsChunk; + get.sections = sections.clone(); + get.reset(); + } + if (get.sections == null) { + get.sections = sections.clone(); + } + if (get.sections[layer] != section) { + get.sections[layer] = section; + } + get.blocks[layer] = arr; + } + } + + private void removeEntity(Entity entity) { + entity.die(); + entity.valid = false; + } + + @Override + public synchronized T call() { + try { + int X = getX(); + int Z = getZ(); + BukkitQueue extent = (BukkitQueue) getExtent(); + BukkitGetBlocks get = (BukkitGetBlocks) getOrCreateGet(); + IChunkSet set = getOrCreateSet(); + + Chunk nmsChunk = extent.ensureLoaded(X, Z); + + // Remove existing tiles + { + Map tiles = nmsChunk.getTileEntities(); + if (!tiles.isEmpty()) { + final Iterator> iterator = tiles.entrySet().iterator(); + while (iterator.hasNext()) { + final Map.Entry entry = iterator.next(); + final BlockPosition pos = entry.getKey(); + final int lx = pos.getX() & 15; + final int ly = pos.getY(); + final int lz = pos.getZ() & 15; + final int layer = ly >> 4; + if (!set.hasSection(layer)) { + continue; + } + if (set.getBlock(lx, ly, lz).getOrdinal() != 0) { + TileEntity tile = entry.getValue(); + tile.n(); + tile.invalidateBlockCache(); + } + } + } + } + + int bitMask = 0; + synchronized (nmsChunk) { + ChunkSection[] sections = nmsChunk.getSections(); + World world = extent.getBukkitWorld(); + boolean hasSky = world.getEnvironment() == World.Environment.NORMAL; + + for (int layer = 0; layer < 16; layer++) { + if (!set.hasSection(layer)) continue; + + bitMask |= 1 << layer; + + char[] setArr = set.getArray(layer); + ChunkSection newSection; + ChunkSection existingSection = sections[layer]; + if (existingSection == null) { + newSection = extent.newChunkSection(layer, setArr); + if (BukkitQueue.setSectionAtomic(sections, null, newSection, layer)) { + updateGet(get, nmsChunk, sections, newSection, setArr, layer); + continue; + } else { + existingSection = sections[layer]; + if (existingSection == null) { + System.out.println("Skipping invalid null section. chunk:" + X + "," + Z + " layer: " + layer); + continue; + } + } + } + DelegateLock lock = BukkitQueue.applyLock(existingSection); + synchronized (get) { + synchronized (lock) { + lock.untilFree(); + + ChunkSection getSection; + if (get.nmsChunk != nmsChunk) { + get.nmsChunk = nmsChunk; + get.sections = null; + get.reset(); + } else { + getSection = get.getSections()[layer]; + if (getSection != existingSection) { + get.sections[layer] = existingSection; + get.reset(); + } else if (lock.isModified()) { + get.reset(layer); + } + } + char[] getArr = get.load(layer); + for (int i = 0; i < 4096; i++) { + char value = setArr[i]; + if (value != 0) { + getArr[i] = value; + } + } + newSection = extent.newChunkSection(layer, getArr); + if (!BukkitQueue.setSectionAtomic(sections, existingSection, newSection, layer)) { + System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer); + continue; + } else { + updateGet(get, nmsChunk, sections, newSection, setArr, layer); + } + } + } + } + + // Biomes + BiomeType[] biomes = set.getBiomes(); + if (biomes != null) { + // set biomes + final BiomeBase[] currentBiomes = nmsChunk.getBiomeIndex(); + for (int i = 0; i < biomes.length; i++) { + final BiomeType biome = biomes[i]; + if (biome != null) { + final Biome craftBiome = BukkitAdapter.adapt(biome); + currentBiomes[i] = CraftBlock.biomeToBiomeBase(craftBiome); + } + } + } + + Runnable[] syncTasks = null; + + net.minecraft.server.v1_14_R1.World nmsWorld = nmsChunk.getWorld(); + int bx = X << 4; + int bz = Z << 4; + + Set entityRemoves = set.getEntityRemoves(); + if (entityRemoves != null && !entityRemoves.isEmpty()) { + if (syncTasks == null) syncTasks = new Runnable[3]; + + syncTasks[2] = new Runnable() { + @Override + public void run() { + final List[] entities = nmsChunk.getEntitySlices(); + + for (int i = 0; i < entities.length; i++) { + final Collection ents = entities[i]; + if (!ents.isEmpty()) { + final Iterator iter = ents.iterator(); + while (iter.hasNext()) { + final Entity entity = iter.next(); + if (entityRemoves.contains(entity.getUniqueID())) { + iter.remove(); + removeEntity(entity); + } + } + } + } + } + }; + } + + Set entities = set.getEntities(); + if (entities != null && !entities.isEmpty()) { + if (syncTasks == null) syncTasks = new Runnable[2]; + + syncTasks[1] = new Runnable() { + @Override + public void run() { + for (final CompoundTag nativeTag : entities) { + final Map entityTagMap = ReflectionUtils.getMap(nativeTag.getValue()); + final StringTag idTag = (StringTag) entityTagMap.get("Id"); + final ListTag posTag = (ListTag) entityTagMap.get("Pos"); + final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); + if (idTag == null || posTag == null || rotTag == null) { + Fawe.debug("Unknown entity tag: " + nativeTag); + continue; + } + final double x = posTag.getDouble(0); + final double y = posTag.getDouble(1); + final double z = posTag.getDouble(2); + final float yaw = rotTag.getFloat(0); + final float pitch = rotTag.getFloat(1); + final String id = idTag.getValue(); + + EntityTypes type = EntityTypes.a(id).orElse(null); + if (type != null) { + Entity entity = type.a(nmsWorld); + if (entity != null) { + UUID uuid = entity.getUniqueID(); + entityTagMap.put("UUIDMost", new LongTag(uuid.getMostSignificantBits())); + entityTagMap.put("UUIDLeast", new LongTag(uuid.getLeastSignificantBits())); + if (nativeTag != null) { + final NBTTagCompound tag = (NBTTagCompound) BukkitQueue_1_14.fromNative(nativeTag); + for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { + tag.remove(name); + } + entity.f(tag); + } + entity.setLocation(x, y, z, yaw, pitch); + nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM); + } + } + } + } + }; + + } + + // set tiles + Map tiles = set.getTiles(); + if (tiles != null && !tiles.isEmpty()) { + if (syncTasks == null) syncTasks = new Runnable[1]; + + syncTasks[0] = new Runnable() { + @Override + public void run() { + for (final Map.Entry entry : tiles.entrySet()) { + final CompoundTag nativeTag = entry.getValue(); + final short blockHash = entry.getKey(); + final int x = (blockHash >> 12 & 0xF) + bx; + final int y = (blockHash & 0xFF); + final int z = (blockHash >> 8 & 0xF) + bz; + final BlockPosition pos = new BlockPosition(x, y, z); + synchronized (nmsWorld) { + TileEntity tileEntity = nmsWorld.getTileEntity(pos); + if (tileEntity == null || tileEntity.isRemoved()) { + nmsWorld.removeTileEntity(pos); + tileEntity = nmsWorld.getTileEntity(pos); + } + if (tileEntity != null) { + final NBTTagCompound tag = (NBTTagCompound) fromNative(nativeTag); + tag.set("x", new NBTTagInt(x)); + tag.set("y", new NBTTagInt(y)); + tag.set("z", new NBTTagInt(z)); + tileEntity.load(tag); + } + } + } + } + }; + } + + Runnable callback; + if (bitMask == 0) { + callback = null; + } else { + int finalMask = bitMask; + callback = () -> { + // Set Modified + nmsChunk.d(true); // Set Modified + nmsChunk.mustNotSave = false; + nmsChunk.markDirty(); + // send to player + extent.sendChunk(X, Z, finalMask); + + extent.returnToPool(BukkitChunkHolder.this); + }; + } + if (syncTasks != null) { + QueueHandler queueHandler = Fawe.get().getQueueHandler(); + Runnable[] finalSyncTasks = syncTasks; + + // Chain the sync tasks and the callback + Callable chain = new Callable() { + @Override + public Future call() { + // Run the sync tasks + for (int i = 1; i < finalSyncTasks.length; i++) { + Runnable task = finalSyncTasks[i]; + if (task != null) { + task.run(); + } + } + if (callback == null) { + extent.returnToPool(BukkitChunkHolder.this); + return null; + } else { + return queueHandler.async(callback, null); + } + } + }; + return (T) (Future) queueHandler.sync(chain); + } else { + if (callback == null) { + extent.returnToPool(BukkitChunkHolder.this); + } else { + callback.run(); + } + } + } + return null; + } catch (Throwable e) { + e.printStackTrace(); + return null; + } + } +} \ No newline at end of file diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java new file mode 100644 index 000000000..256268ec5 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java @@ -0,0 +1,211 @@ +package com.boydti.fawe.bukkit.beta; + +import com.boydti.fawe.FaweCache; +import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; +import com.boydti.fawe.bukkit.v1_14.BukkitQueue_1_14; +import com.boydti.fawe.bukkit.v1_14.adapter.Spigot_v1_14_R1; +import com.boydti.fawe.jnbt.anvil.BitArray4096; +import com.boydti.fawe.util.MemUtil; +import com.boydti.fawe.util.TaskManager; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockTypes; +import net.minecraft.server.v1_14_R1.BiomeBase; +import net.minecraft.server.v1_14_R1.Chunk; +import net.minecraft.server.v1_14_R1.ChunkCoordIntPair; +import net.minecraft.server.v1_14_R1.ChunkProviderServer; +import net.minecraft.server.v1_14_R1.ChunkSection; +import net.minecraft.server.v1_14_R1.DataBits; +import net.minecraft.server.v1_14_R1.DataPalette; +import net.minecraft.server.v1_14_R1.DataPaletteBlock; +import net.minecraft.server.v1_14_R1.DataPaletteHash; +import net.minecraft.server.v1_14_R1.DataPaletteLinear; +import net.minecraft.server.v1_14_R1.IBlockData; +import net.minecraft.server.v1_14_R1.World; +import net.minecraft.server.v1_14_R1.WorldServer; +import org.bukkit.craftbukkit.v1_14_R1.block.CraftBlock; + +import java.util.Arrays; + +public class BukkitGetBlocks extends CharGetBlocks { + public ChunkSection[] sections; + public Chunk nmsChunk; + public World nmsWorld; + public int X, Z; + private boolean forceLoad; + + public BukkitGetBlocks(World nmsWorld, int X, int Z, boolean forceLoad) { + this.nmsWorld = nmsWorld; + this.X = X; + this.Z = Z; + if (forceLoad) { + ((WorldServer) nmsWorld).setForceLoaded(X, Z, this.forceLoad = true); + } + } + + @Override + protected void finalize() { + if (forceLoad) { + ((WorldServer) nmsWorld).setForceLoaded(X, Z, forceLoad = false); + } + } + + @Override + public BiomeType getBiomeType(int x, int z) { + BiomeBase base = getChunk().getBiomeIndex()[(z << 4) + x]; + return BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(base)); + } + + @Override + public CompoundTag getTag(int x, int y, int z) { + // TODO + return null; + } + + @Override + public char[] load(int layer) { + return load(layer, null); + } + + @Override + public synchronized char[] load(int layer, char[] data) { + ChunkSection section = getSections()[layer]; + // Section is null, return empty array + if (section == null) { + return FaweCache.EMPTY_CHAR_4096; + } + if (data == null || data == FaweCache.EMPTY_CHAR_4096) { + data = new char[4096]; + } + DelegateLock lock = BukkitQueue.applyLock(section); + synchronized (lock) { + lock.untilFree(); + lock.setModified(false); + // Efficiently convert ChunkSection to raw data + try { + Spigot_v1_14_R1 adapter = ((Spigot_v1_14_R1) WorldEditPlugin.getInstance().getBukkitImplAdapter()); + + final DataPaletteBlock blocks = section.getBlocks(); + final DataBits bits = (DataBits) BukkitQueue_1_14.fieldBits.get(blocks); + final DataPalette palette = (DataPalette) BukkitQueue_1_14.fieldPalette.get(blocks); + + final int bitsPerEntry = bits.c(); + final long[] blockStates = bits.a(); + + new BitArray4096(blockStates, bitsPerEntry).toRaw(data); + + int num_palette; + if (palette instanceof DataPaletteLinear) { + num_palette = ((DataPaletteLinear) palette).b(); + } else if (palette instanceof DataPaletteHash) { + num_palette = ((DataPaletteHash) palette).b(); + } else { + num_palette = 0; + int[] paletteToBlockInts = FaweCache.PALETTE_TO_BLOCK.get(); + char[] paletteToBlockChars = FaweCache.PALETTE_TO_BLOCK_CHAR.get(); + try { + for (int i = 0; i < 4096; i++) { + char paletteVal = data[i]; + char ordinal = paletteToBlockChars[paletteVal]; + if (ordinal == Character.MAX_VALUE) { + paletteToBlockInts[num_palette++] = paletteVal; + IBlockData ibd = palette.a(data[i]); + if (ibd == null) { + ordinal = BlockTypes.AIR.getDefaultState().getOrdinalChar(); + } else { + ordinal = adapter.adaptToChar(ibd); + } + paletteToBlockChars[paletteVal] = ordinal; + } + data[i] = ordinal; + } + } finally { + for (int i = 0; i < num_palette; i++) { + int paletteVal = paletteToBlockInts[i]; + paletteToBlockChars[paletteVal] = Character.MAX_VALUE; + } + } + return data; + } + + char[] paletteToBlockChars = FaweCache.PALETTE_TO_BLOCK_CHAR.get(); + try { + final int size = num_palette; + if (size != 1) { + for (int i = 0; i < size; i++) { + char ordinal = ordinal(palette.a(i), adapter); + paletteToBlockChars[i] = ordinal; + } + for (int i = 0; i < 4096; i++) { + char paletteVal = data[i]; + char val = paletteToBlockChars[paletteVal]; + data[i] = val; + } + } else { + char ordinal = ordinal(palette.a(0), adapter); + Arrays.fill(data, ordinal); + } + } finally { + for (int i = 0; i < num_palette; i++) { + paletteToBlockChars[i] = Character.MAX_VALUE; + } + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + return data; + } + } + + private final char ordinal(IBlockData ibd, Spigot_v1_14_R1 adapter) { + if (ibd == null) { + return BlockTypes.AIR.getDefaultState().getOrdinalChar(); + } else { + return adapter.adaptToChar(ibd); + } + } + + public ChunkSection[] getSections() { + ChunkSection[] tmp = sections; + if (tmp == null) { + synchronized (this) { + tmp = sections; + if (tmp == null) { + Chunk chunk = getChunk(); + sections = tmp = chunk.getSections().clone(); + } + } + } + return tmp; + } + + public Chunk getChunk() { + Chunk tmp = nmsChunk; + if (tmp == null) { + synchronized (this) { + tmp = nmsChunk; + if (tmp == null) { + nmsChunk = tmp = BukkitQueue.ensureLoaded(nmsWorld, X, Z); + } + } + } + return tmp; + } + + @Override + public boolean hasSection(int layer) { + return getSections()[layer] != null; + } + + @Override + public boolean trim(boolean aggressive) { + if (aggressive) { + sections = null; + nmsChunk = null; + } + return super.trim(aggressive); + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java new file mode 100644 index 000000000..4cb3896bf --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java @@ -0,0 +1,365 @@ +package com.boydti.fawe.bukkit.beta; + +import com.boydti.fawe.Fawe; +import com.boydti.fawe.FaweCache; +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.implementation.SimpleCharQueueExtent; +import com.boydti.fawe.beta.implementation.WorldChunkCache; +import com.boydti.fawe.bukkit.v1_14.adapter.BlockMaterial_1_14; +import com.boydti.fawe.config.Settings; +import com.boydti.fawe.jnbt.anvil.BitArray4096; +import com.boydti.fawe.util.MathMan; +import com.boydti.fawe.util.TaskManager; +import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BlockID; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; +import net.jpountz.util.UnsafeUtils; +import net.minecraft.server.v1_14_R1.Block; +import net.minecraft.server.v1_14_R1.Chunk; +import net.minecraft.server.v1_14_R1.ChunkCoordIntPair; +import net.minecraft.server.v1_14_R1.ChunkProviderServer; +import net.minecraft.server.v1_14_R1.ChunkSection; +import net.minecraft.server.v1_14_R1.ChunkStatus; +import net.minecraft.server.v1_14_R1.DataBits; +import net.minecraft.server.v1_14_R1.DataPalette; +import net.minecraft.server.v1_14_R1.DataPaletteBlock; +import net.minecraft.server.v1_14_R1.DataPaletteLinear; +import net.minecraft.server.v1_14_R1.GameProfileSerializer; +import net.minecraft.server.v1_14_R1.IBlockData; +import net.minecraft.server.v1_14_R1.IChunkAccess; +import net.minecraft.server.v1_14_R1.PlayerChunk; +import net.minecraft.server.v1_14_R1.PlayerChunkMap; +import net.minecraft.server.v1_14_R1.ProtoChunkExtension; +import net.minecraft.server.v1_14_R1.WorldServer; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_14_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_14_R1.CraftWorld; +import sun.misc.Unsafe; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.locks.Lock; +import java.util.function.Supplier; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class BukkitQueue extends SimpleCharQueueExtent { + + private org.bukkit.World bukkitWorld; + private WorldServer nmsWorld; + + @Override + public synchronized void init(WorldChunkCache cache) { + World world = cache.getWorld(); + if (world instanceof BukkitWorld) { + this.bukkitWorld = ((BukkitWorld) world).getWorld(); + } else { + this.bukkitWorld = Bukkit.getWorld(world.getName()); + } + checkNotNull(this.bukkitWorld); + CraftWorld craftWorld = ((CraftWorld) bukkitWorld); + this.nmsWorld = craftWorld.getHandle(); + super.init(cache); + } + + public WorldServer getNmsWorld() { + return nmsWorld; + } + + public org.bukkit.World getBukkitWorld() { + return bukkitWorld; + } + + @Override + protected synchronized void reset() { + super.reset(); + } + +// private static final IterableThreadLocal FULL_CHUNKS = new IterableThreadLocal() { +// @Override +// public BukkitFullChunk init() { +// return new BukkitFullChunk(); +// } +// }; + + @Override + public IChunk create(boolean full) { +// if (full) { +// //TODO implement +// return FULL_CHUNKS.get(); +// } + return new BukkitChunkHolder(); + } + + /* + NMS fields + */ + public final static Field fieldBits; + public final static Field fieldPalette; + public final static Field fieldSize; + + public final static Field fieldFluidCount; + public final static Field fieldTickingBlockCount; + public final static Field fieldNonEmptyBlockCount; + + private final static Field fieldDirtyCount; + private final static Field fieldDirtyBits; + + private static final int CHUNKSECTION_BASE; + private static final int CHUNKSECTION_SHIFT; + + private static final Field fieldLock; + + static { + try { + fieldSize = DataPaletteBlock.class.getDeclaredField("i"); + fieldSize.setAccessible(true); + fieldBits = DataPaletteBlock.class.getDeclaredField("a"); + fieldBits.setAccessible(true); + fieldPalette = DataPaletteBlock.class.getDeclaredField("h"); + fieldPalette.setAccessible(true); + + fieldFluidCount = ChunkSection.class.getDeclaredField("e"); + fieldFluidCount.setAccessible(true); + fieldTickingBlockCount = ChunkSection.class.getDeclaredField("tickingBlockCount"); + fieldTickingBlockCount.setAccessible(true); + fieldNonEmptyBlockCount = ChunkSection.class.getDeclaredField("nonEmptyBlockCount"); + fieldNonEmptyBlockCount.setAccessible(true); + + fieldDirtyCount = PlayerChunk.class.getDeclaredField("dirtyCount"); + fieldDirtyCount.setAccessible(true); + fieldDirtyBits = PlayerChunk.class.getDeclaredField("h"); + fieldDirtyBits.setAccessible(true); + + { + Field tmp = null; + try { + tmp = DataPaletteBlock.class.getDeclaredField("j"); + } catch (NoSuchFieldException paper) { + tmp = DataPaletteBlock.class.getDeclaredField("writeLock"); + } + fieldLock = tmp; + fieldLock.setAccessible(true); + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + int modifiers = modifiersField.getInt(fieldLock); + int newModifiers = modifiers & (~Modifier.FINAL); + if (newModifiers != modifiers) modifiersField.setInt(fieldLock, newModifiers); + } + + Unsafe unsafe = UnsafeUtils.getUNSAFE(); + CHUNKSECTION_BASE = unsafe.arrayBaseOffset(ChunkSection[].class); + int scale = unsafe.arrayIndexScale(ChunkSection[].class); + if ((scale & (scale - 1)) != 0) + throw new Error("data type scale not a power of two"); + CHUNKSECTION_SHIFT = 31 - Integer.numberOfLeadingZeros(scale); + } catch (RuntimeException e) { + throw e; + } catch (Throwable rethrow) { + rethrow.printStackTrace(); + throw new RuntimeException(rethrow); + } + } + + protected static boolean setSectionAtomic(ChunkSection[] sections, ChunkSection expected, ChunkSection value, int layer) { + long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE; + if (layer >= 0 && layer < sections.length) { + return UnsafeUtils.getUNSAFE().compareAndSwapObject(sections, offset, expected, value); + } + return false; + } + + protected static DelegateLock applyLock(ChunkSection section) { + try { + synchronized (section) { + DataPaletteBlock blocks = section.getBlocks(); + Lock currentLock = (Lock) fieldLock.get(blocks); + if (currentLock instanceof DelegateLock) { + return (DelegateLock) currentLock; + } + DelegateLock newLock = new DelegateLock(currentLock); + fieldLock.set(blocks, newLock); + return newLock; + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + private static boolean PAPER = true; + + public Chunk ensureLoaded(int X, int Z) { + return ensureLoaded(nmsWorld, X, Z); + } + + public static Chunk ensureLoaded(net.minecraft.server.v1_14_R1.World nmsWorld, int X, int Z) { + Chunk nmsChunk = nmsWorld.getChunkIfLoaded(X, Z); + if (nmsChunk != null) { + return nmsChunk; + } + if (Fawe.isMainThread()) { + return nmsWorld.getChunkAt(X, Z); + } + if (PAPER) { + CraftWorld craftWorld = nmsWorld.getWorld(); + CompletableFuture future = craftWorld.getChunkAtAsync(X, Z, true); + try { + CraftChunk chunk = (CraftChunk) future.get(); + return chunk.getHandle(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } catch (Throwable e) { + System.out.println("Error, cannot load chunk async (paper not installed?)"); + PAPER = false; + } + } + // TODO optimize + return TaskManager.IMP.sync(() -> nmsWorld.getChunkAt(X, Z)); + } + + private PlayerChunk getPlayerChunk(final int cx, final int cz) { + PlayerChunkMap chunkMap = nmsWorld.getChunkProvider().playerChunkMap; + PlayerChunk playerChunk = chunkMap.visibleChunks.get(ChunkCoordIntPair.pair(cx, cz)); + if (playerChunk == null) { + return null; + } + return playerChunk; + } + + public boolean sendChunk(final int X, final int Z, final int mask) { + PlayerChunk playerChunk = getPlayerChunk(X, Z); + if (playerChunk == null) { + return false; + } +// ChunkSection[] sections = nmsChunk.getSections(); +// for (int layer = 0; layer < 16; layer++) { +// if (sections[layer] == null && (mask & (1 << layer)) != 0) { +// sections[layer] = new ChunkSection(layer << 4); +// } +// } + if (playerChunk.k()) { + TaskManager.IMP.sync(new Supplier() { + @Override + public Object get() { + try { + int dirtyBits = fieldDirtyBits.getInt(playerChunk); + if (dirtyBits == 0) { + nmsWorld.getChunkProvider().playerChunkMap.a(playerChunk); + } + if (mask == 0) { + dirtyBits = 65535; + } else { + dirtyBits |= mask; + } + + fieldDirtyBits.set(playerChunk, dirtyBits); + fieldDirtyCount.set(playerChunk, 64); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + return null; + } + }); + return true; + } + return false; + } + + /* + NMS conversion + */ + + public static ChunkSection newChunkSection(final int layer, final char[] blocks) { + ChunkSection section = new ChunkSection(layer << 4); + if (blocks == null) { + return section; + } + final int[] blockToPalette = FaweCache.BLOCK_TO_PALETTE.get(); + final int[] paletteToBlock = FaweCache.PALETTE_TO_BLOCK.get(); + final long[] blockstates = FaweCache.BLOCK_STATES.get(); + final int[] blocksCopy = FaweCache.SECTION_BLOCKS.get(); + try { + int num_palette = 0; + int air = 0; + for (int i = 0; i < 4096; i++) { + char ordinal = blocks[i]; + switch (ordinal) { + case 0: + case BlockID.AIR: + case BlockID.CAVE_AIR: + case BlockID.VOID_AIR: + air++; + } + int palette = blockToPalette[ordinal]; + if (palette == Integer.MAX_VALUE) { + blockToPalette[ordinal] = palette = num_palette; + paletteToBlock[num_palette] = ordinal; + num_palette++; + } + blocksCopy[i] = palette; + } + + // BlockStates + int bitsPerEntry = MathMan.log2nlz(num_palette - 1); + if (Settings.IMP.PROTOCOL_SUPPORT_FIX || num_palette != 1) { + bitsPerEntry = Math.max(bitsPerEntry, 4); // Protocol support breaks <4 bits per entry + } else { + bitsPerEntry = Math.max(bitsPerEntry, 1); // For some reason minecraft needs 4096 bits to store 0 entries + } + + final int blockBitArrayEnd = (bitsPerEntry * 4096) >> 6; + if (num_palette == 1) { + for (int i = 0; i < blockBitArrayEnd; i++) blockstates[i] = 0; + } else { + final BitArray4096 bitArray = new BitArray4096(blockstates, bitsPerEntry); + bitArray.fromRaw(blocksCopy); + } + + // set palette & data bits + final DataPaletteBlock dataPaletteBlocks = section.getBlocks(); + // private DataPalette h; + // protected DataBits a; + final long[] bits = Arrays.copyOfRange(blockstates, 0, blockBitArrayEnd); + final DataBits nmsBits = new DataBits(bitsPerEntry, 4096, bits); + final DataPalette palette; +// palette = new DataPaletteHash<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::d, GameProfileSerializer::a); + palette = new DataPaletteLinear<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::d); + + // set palette + for (int i = 0; i < num_palette; i++) { + final int ordinal = paletteToBlock[i]; + blockToPalette[ordinal] = Integer.MAX_VALUE; + final BlockState state = BlockTypes.states[ordinal]; + final IBlockData ibd = ((BlockMaterial_1_14) state.getMaterial()).getState(); + palette.a(ibd); + } + try { + fieldBits.set(dataPaletteBlocks, nmsBits); + fieldPalette.set(dataPaletteBlocks, palette); + fieldSize.set(dataPaletteBlocks, bitsPerEntry); + setCount(0, 4096 - air, section); + } catch (final IllegalAccessException | NoSuchFieldException e) { + throw new RuntimeException(e); + } + + return section; + } catch (final Throwable e){ + Arrays.fill(blockToPalette, Integer.MAX_VALUE); + throw e; + } + } + + public static void setCount(final int tickingBlockCount, final int nonEmptyBlockCount, final ChunkSection section) throws NoSuchFieldException, IllegalAccessException { + fieldFluidCount.set(section, 0); // TODO FIXME + fieldTickingBlockCount.set(section, tickingBlockCount); + fieldNonEmptyBlockCount.set(section, nonEmptyBlockCount); + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueueHandler.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueueHandler.java new file mode 100644 index 000000000..00528d29a --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueueHandler.java @@ -0,0 +1,11 @@ +package com.boydti.fawe.bukkit.beta; + +import com.boydti.fawe.beta.IQueueExtent; +import com.boydti.fawe.beta.implementation.QueueHandler; + +public class BukkitQueueHandler extends QueueHandler { + @Override + public IQueueExtent create() { + return new BukkitQueue(); + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/DelegateLock.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/DelegateLock.java new file mode 100644 index 000000000..6d79d967e --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/DelegateLock.java @@ -0,0 +1,123 @@ +package com.boydti.fawe.bukkit.beta; + +import org.apache.commons.lang.mutable.MutableInt; + +import java.util.Collection; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.LongAdder; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +public class DelegateLock extends ReentrantLock { + private final Lock parent; + private volatile boolean modified; + private final AtomicInteger count; + + public DelegateLock(Lock parent) { + this.parent = parent; + if (!(parent instanceof ReentrantLock)) { + count = new AtomicInteger(); + } else { + count = null; + } + } + + public boolean isModified() { + return modified; + } + + public void setModified(boolean modified) { + this.modified = modified; + } + + @Override + public synchronized void lock() { + modified = true; + parent.lock(); + if (count != null) { + count.incrementAndGet(); + } + } + + @Override + public synchronized void lockInterruptibly() throws InterruptedException { + parent.lockInterruptibly(); + } + + @Override + public synchronized boolean tryLock() { + return parent.tryLock(); + } + + @Override + public synchronized boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { + return parent.tryLock(timeout, unit); + } + + @Override + public void unlock() { + modified = true; + parent.unlock(); + if (count != null) { + if (count.getAndDecrement() <= 0) { + count.incrementAndGet(); + } + } + } + + public Lock getParent() { + return parent; + } + + @Override + public synchronized Condition newCondition() { + return parent.newCondition(); + } + + @Override + public synchronized int getHoldCount() { + throw new UnsupportedOperationException(); + } + + @Override + public synchronized boolean isHeldByCurrentThread() { + throw new UnsupportedOperationException(); + } + + @Override + public synchronized boolean isLocked() { + if (parent instanceof ReentrantLock) { + return ((ReentrantLock) parent).isLocked(); + } + return count.get() > 0; + } + + public void untilFree() { + if (parent instanceof ReentrantLock) { + ReentrantLock rl = (ReentrantLock) parent; + if (rl.isLocked()) { + rl.lock(); + rl.unlock(); + } + return; + } + while (count.get() > 0); + } + + @Override + public synchronized boolean hasWaiters(Condition condition) { + throw new UnsupportedOperationException(); + } + + @Override + public synchronized int getWaitQueueLength(Condition condition) { + throw new UnsupportedOperationException(); + } + + @Override + public synchronized String toString() { + return parent.toString(); + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/listener/CFIPacketListener.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/listener/CFIPacketListener.java index 980f8abc8..cec672dd0 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/listener/CFIPacketListener.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/listener/CFIPacketListener.java @@ -85,11 +85,17 @@ public class CFIPacketListener implements Listener { ItemStack hand = enumHand == EnumWrappers.Hand.MAIN_HAND ? inv.getItemInMainHand() : inv.getItemInOffHand(); if (hand.getType().isBlock()) { Material type = hand.getType(); - if (!type.isEmpty()) { - BlockStateHolder block = BukkitAdapter.asBlockState(hand); - if (block != null) { - gen.setBlock(pt, block); - return; + switch (type) { + case AIR: + case CAVE_AIR: + case VOID_AIR: + break; + default: { + BlockStateHolder block = BukkitAdapter.asBlockState(hand); + if (block != null) { + gen.setBlock(pt, block); + return; + } } } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/listener/RenderListener.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/listener/RenderListener.java index e89b90745..6eae8de1e 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/listener/RenderListener.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/listener/RenderListener.java @@ -96,7 +96,8 @@ public class RenderListener implements Listener { } } } - player.setViewDistance(value); + throw new UnsupportedOperationException("TODO FIXME: PAPER 1.14"); +// player.setViewDistance(value); } private int getViewDistance(Player player) { diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All.java deleted file mode 100644 index f06b31a1b..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All.java +++ /dev/null @@ -1,356 +0,0 @@ -package com.boydti.fawe.bukkit.v0; - -import com.boydti.fawe.Fawe; -import com.boydti.fawe.config.Settings; -import com.boydti.fawe.example.IntFaweChunk; -import com.boydti.fawe.object.FaweChunk; -import com.boydti.fawe.object.FaweQueue; -import com.boydti.fawe.object.RunnableVal2; -import com.boydti.fawe.util.MainUtil; -import com.boydti.fawe.util.ReflectionUtils; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.LongTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.entity.Player; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.block.BlockTypes; -import com.sk89q.worldedit.world.entity.EntityTypes; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.ChunkSnapshot; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.block.Biome; -import org.bukkit.block.Block; -import org.bukkit.block.BlockState; -import org.bukkit.entity.Entity; - -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - -public class BukkitChunk_All extends IntFaweChunk { - - private int layer = -1; - private int index; - private boolean place = true; - - /** - * A FaweSections object represents a chunk and the blocks that you wish to change in it. - * - * @param parent - * @param x - * @param z - */ - public BukkitChunk_All(FaweQueue parent, int x, int z) { - super(parent, x, z); - } - - public BukkitChunk_All(FaweQueue parent, int x, int z, int[][] ids, short[] count, short[] air) { - super(parent, x, z, ids, count, air); - } - - private static boolean canTick(BlockType type) { - return type.getMaterial().isTicksRandomly(); - } - - @Override - public IntFaweChunk copy(boolean shallow) { - BukkitChunk_All copy; - if (shallow) { - copy = new BukkitChunk_All(getParent(), getX(), getZ(), setBlocks, count, air); - copy.biomes = biomes; - } else { - copy = new BukkitChunk_All(getParent(), getX(), getZ(), (int[][]) MainUtil.copyNd(setBlocks), count.clone(), air.clone()); - copy.biomes = biomes != null ? biomes.clone() : null; - } - copy.chunk = chunk; - return copy; - } - - @Override - public Chunk getNewChunk() { - return Bukkit.getWorld(getParent().getWorldName()).getChunkAt(getX(), getZ()); - } - - @Override - public void start() { - getChunk().load(true); - } - - /** - * @return - */ - @Override - public FaweChunk call() { - long start = System.currentTimeMillis(); - int recommended = 25 + Settings.IMP.QUEUE.EXTRA_TIME_MS; - boolean more = true; - final BukkitQueue_All parent = getParent(); - BukkitImplAdapter adapter = BukkitQueue_0.getAdapter(); - final Chunk chunk = getChunk(); - Object[] disableResult = parent.disableLighting(chunk); - final World world = chunk.getWorld(); - int[][] sections = getCombinedIdArrays(); - final int bx = getX() << 4; - final int bz = getZ() << 4; - boolean update = adapter == null || adapter.isChunkInUse(chunk); - if (layer == -1) { - if (adapter != null) { - // Run change task - RunnableVal2 task = parent.getChangeTask(); - BukkitChunk_All_ReadonlySnapshot previous; - if (task != null) { - ChunkSnapshot snapshot = parent.ensureChunkLoaded(getX(), getZ()); - previous = new BukkitChunk_All_ReadonlySnapshot(parent, this, snapshot, biomes != null); - for (BlockState tile : chunk.getTileEntities()) { - int x = tile.getX(); - int y = tile.getY(); - int z = tile.getZ(); - if (getBlockCombinedId(x & 15, y, z & 15) != 0) { - CompoundTag nbt = adapter.getBlock(new Location(world, x, y, z)).getNbtData(); - if (nbt != null) { - previous.setTile(x & 15, y, z & 15, nbt); - } - } - } - } else { - previous = null; - } - // Set entities - if (adapter != null) { - Set entitiesToSpawn = this.getEntities(); - if (!entitiesToSpawn.isEmpty()) { - for (CompoundTag tag : entitiesToSpawn) { - String id = tag.getString("Id"); - ListTag posTag = tag.getListTag("Pos"); - ListTag rotTag = tag.getListTag("Rotation"); - if (id == null || posTag == null || rotTag == null) { - Fawe.debug("Unknown entity tag: " + tag); - continue; - } - double x = posTag.getDouble(0); - double y = posTag.getDouble(1); - double z = posTag.getDouble(2); - float yaw = rotTag.getFloat(0); - float pitch = rotTag.getFloat(1); - Location loc = new Location(world, x, y, z, yaw, pitch); - Entity created = adapter.createEntity(loc, new BaseEntity(EntityTypes.get(id), tag)); - if (created != null) { - UUID uuid = created.getUniqueId(); - Map map = ReflectionUtils.getMap(tag.getValue()); - map.put("UUIDLeast", new LongTag(uuid.getLeastSignificantBits())); - map.put("UUIDMost", new LongTag(uuid.getMostSignificantBits())); - } - } - } - HashSet entsToRemove = this.getEntityRemoves(); - if (!entsToRemove.isEmpty()) { - for (Entity entity : chunk.getEntities()) { - if (entsToRemove.contains(entity.getUniqueId()) && !(entity instanceof Player)) { - entity.remove(); - } - } - } - } - if (previous != null) { - task.run(previous, this); - } - } - - // Biomes - final BiomeType[] biomes = getBiomeArray(); - if (biomes != null) { - int index = 0; - for (int z = 0; z < 16; z++) { - int zz = bz + z; - for (int x = 0; x < 16; x++, index++) { - int xx = bx + x; - BiomeType biome = biomes[index]; - if (biome == null) continue; - Biome bukkitBiome = adapter.adapt(biome); - if (bukkitBiome != null) { - world.setBiome(xx, zz, bukkitBiome); - } - } - } - } - } else if (index != 0) { - if (place) { - layer--; - } else { - layer++; - } - } - mainloop: - do { - if (place) { - if (++layer >= sections.length) { - place = false; - layer = sections.length - 1; - } - } else if (--layer < 0) { - more = false; - break; - } - try { - // Efficiently merge sections - int changes = getCount(layer); - if (changes == 0) { - continue; - } - final int[] newArray = sections[layer]; - if (newArray == null) { - continue; - } -// final byte[] cacheX = FaweCache.CACHE_X[layer]; -// final short[] cacheY = FaweCache.CACHE_Y[layer]; -// final byte[] cacheZ = FaweCache.CACHE_Z[layer]; - boolean checkTime = !((getAir(layer) == 4096 || (getCount(layer) == 4096 && getAir(layer) == 0) || (getCount(layer) == getAir(layer)))); - - Location mutableLoc = new Location(world, 0, 0, 0); - - if (!checkTime) { - int index = 0; - for (int y = 0; y < 16; y++) { - int yy = (layer << 4) + y; - for (int z = 0; z < 16; z++) { - int zz = bz + z; - for (int x = 0; x < 16; x++, index++) { - int combined = newArray[index]; - if (combined == 0) continue; - int xx = bx + x; - - BlockType type = BlockTypes.getFromStateId(combined); - if (type == BlockTypes.__RESERVED__) continue; - if (type.getMaterial().isAir()) { - if (!place) { - mutableLoc.setX(xx); - mutableLoc.setY(yy); - mutableLoc.setZ(zz); - setBlock(adapter, chunk, mutableLoc, combined, update); - } - continue; - } - if (place) { - if (type.getMaterial().hasContainer() && adapter != null) { - CompoundTag nbt = getTile(x, yy, z); - if (nbt != null) { - synchronized (BukkitChunk_All.this) { - BaseBlock state = - BaseBlock.getFromInternalId(combined, nbt); - adapter.setBlock(chunk, xx, yy, zz, state, update); - } - continue; - } - } - if (type.getMaterial().isTicksRandomly()) { - synchronized (BukkitChunk_All.this) { - setBlock(adapter, chunk, mutableLoc, combined, update); - } - } else { - mutableLoc.setX(xx); - mutableLoc.setY(yy); - mutableLoc.setZ(zz); - setBlock(adapter, chunk, mutableLoc, combined, update); - } - } - } - } - } - } else { - int yStart = layer << 4; - for (; index < 4096; index++) { - int j = place ? index : 4095 - index; - int combined = newArray[j]; - if (combined == 0) continue; - BlockType type = BlockTypes.getFromStateId(combined); - if (type.getMaterial().isAir()) { - if (!place) { - int x = j & 15; - int y = yStart + (j >> 8); - int z = (j >> 4) & 15; - mutableLoc.setX(bx + x); - mutableLoc.setY(y); - mutableLoc.setZ(bz + z); - setBlock(adapter, chunk, mutableLoc, combined, update); - } - continue; - } else { - boolean light = type.getMaterial().getLightValue() > 0; - if (light) { - if (place) { - continue; - } - light = light && getParent().getSettings().LIGHTING.MODE != 0; - if (light) { - parent.enableLighting(disableResult); - } - } else if (!place) { - continue; - } - int x = j & 15; - int y = yStart + (j >> 8); - int z = (j >> 4) & 15; - if (type.getMaterial().hasContainer() && adapter != null) { - CompoundTag tile = getTile(x, y, z); - if (tile != null) { - synchronized (BukkitChunk_All.this) { - BaseBlock state = BaseBlock.getFromInternalId(combined, tile); - adapter.setBlock(chunk, bx + x, y, bz + z, state, update); - } - continue; - } - } - if (type.getMaterial().isTicksRandomly()) { - synchronized (BukkitChunk_All.this) { - mutableLoc.setX(bx + x); - mutableLoc.setY(y); - mutableLoc.setZ(bz + z); - setBlock(adapter, chunk, mutableLoc, combined, update); - } - } else { - mutableLoc.setX(bx + x); - mutableLoc.setY(y); - mutableLoc.setZ(bz + z); - setBlock(adapter, chunk, mutableLoc, combined, update); - } - if (light) { - parent.disableLighting(disableResult); - } - } - if (System.currentTimeMillis() - start > recommended) { - index++; - break mainloop; - } - } - index = 0; - } - } catch (final Throwable e) { - e.printStackTrace(); - } - } while (System.currentTimeMillis() - start < recommended); - if (more || place) { - this.addToQueue(); - } - parent.resetLighting(disableResult); - return this; - } - - public void setBlock(BukkitImplAdapter adapter, Chunk chunk, Location location, int combinedId, boolean update) { - com.sk89q.worldedit.world.block.BaseBlock base = com.sk89q.worldedit.world.block.BlockState.getFromInternalId(combinedId).toBaseBlock(); - if (adapter != null) { - adapter.setBlock(chunk, (int) location.getX(), (int) location.getY(), (int) location.getZ(), base, update); - } else { - Block block = location.getWorld().getBlockAt(location); - block.setBlockData(BukkitAdapter.adapt(base), false); - } - } -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All_ReadonlySnapshot.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All_ReadonlySnapshot.java deleted file mode 100644 index 4ed7a4e9a..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All_ReadonlySnapshot.java +++ /dev/null @@ -1,155 +0,0 @@ -package com.boydti.fawe.bukkit.v0; - -import com.boydti.fawe.object.FaweChunk; -import com.boydti.fawe.util.MathMan; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; - -import java.util.*; - -import com.sk89q.worldedit.world.biome.BiomeType; -import org.bukkit.ChunkSnapshot; -import org.bukkit.block.Biome; -import org.bukkit.block.data.BlockData; - -import javax.annotation.Nullable; - -public class BukkitChunk_All_ReadonlySnapshot extends FaweChunk { - private final ChunkSnapshot snapshot; - private final boolean hasBiomes; - private final BukkitChunk_All next; - private Set entities = new HashSet<>(); - private Map tiles = new HashMap<>(); - - public BukkitChunk_All_ReadonlySnapshot(BukkitQueue_All parent, BukkitChunk_All next, ChunkSnapshot snapshot, boolean biomes) { - super(parent, snapshot.getX(), snapshot.getZ()); - this.next = next; - this.snapshot = snapshot; - this.hasBiomes = biomes; - } - - public void setTiles(Map tiles) { - this.tiles = tiles; - } - - public void setEntities(Set entities) { - this.entities = entities; - } - - @Override - public BukkitQueue_All getParent() { - return (BukkitQueue_All) super.getParent(); - } - - @Override - public int getBitMask() { - return Character.MAX_VALUE; - } - - @Override - public int getBlockCombinedId(int x, int y, int z) { - BlockData blockData = snapshot.getBlockData(x, y, z); - return BukkitAdapter.adapt(blockData).getInternalId(); - } - - @Override - public BiomeType[] getBiomeArray() { - if (!hasBiomes || next.biomes == null) return null; - BukkitImplAdapter adapter = getParent().getAdapter(); - BiomeType[] biomes = Arrays.copyOf(next.biomes, next.biomes.length); - int index = 0; - for (int z = 0; z < 16; z++) { - for (int x = 0; x < 16; x++, index++) { - if (biomes[index] != null) { - Biome biome = snapshot.getBiome(x, z); - biomes[index] = adapter.adapt(biome); - } - } - } - return biomes; - } - - @Nullable - @Override - public int[] getIdArray(int layer) { - int[] nextLayer = next.setBlocks[layer]; - if (nextLayer == null) return null; - int[] ids = Arrays.copyOf(nextLayer, nextLayer.length); - int index = 0; - int by = layer << 4; - for (int y = 0; y < 16; y++) { - int yy = by + y; - for (int z = 0; z < 16; z++) { - for (int x = 0; x < 16; x++, index++) { - if (ids[index] != 0) { - ids[index] = getBlockCombinedId(x, yy, z); - } - } - } - } - return ids; - } - - @Override - public Object getChunk() { - return snapshot; - } - - @Override - public void setTile(int x, int y, int z, CompoundTag tile) { - tiles.put(MathMan.tripleBlockCoord(x, y, z), tile); - } - - @Override - public void setEntity(CompoundTag entity) { - entities.add(entity); - } - - @Override - public void removeEntity(UUID uuid) { - throw new UnsupportedOperationException("Read only"); - } - - @Override - public void setBlock(int x, int y, int z, int combinedId) { - throw new UnsupportedOperationException("Read only"); - } - - @Override - public Set getEntities() { - return entities; - } - - @Override - public Set getEntityRemoves() { - throw new UnsupportedOperationException("Read only"); - } - - @Override - public Map getTiles() { - return tiles; - } - - @Override - public CompoundTag getTile(int x, int y, int z) { - if (tiles == null) return null; - short pair = MathMan.tripleBlockCoord(x, y, z); - return tiles.get(pair); - } - - @Override - public void setBiome(int x, int z, BiomeType biome) { - throw new UnsupportedOperationException("Read only"); - } - - @Override - public FaweChunk copy(boolean shallow) { - return null; - } - - @Override - public FaweChunk call() { - return null; - } -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java deleted file mode 100644 index 3ea479f8e..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java +++ /dev/null @@ -1,394 +0,0 @@ -package com.boydti.fawe.bukkit.v0; - -import com.boydti.fawe.Fawe; -import com.boydti.fawe.bukkit.BukkitPlayer; -import com.boydti.fawe.bukkit.FaweBukkit; -import com.boydti.fawe.bukkit.util.BukkitReflectionUtils; -import com.boydti.fawe.example.NMSMappedFaweQueue; -import com.boydti.fawe.object.FaweChunk; -import com.boydti.fawe.object.FawePlayer; -import com.boydti.fawe.object.RunnableVal; -import com.boydti.fawe.object.queue.LazyFaweChunk; -import com.boydti.fawe.object.visitor.FaweChunkVisitor; -import com.boydti.fawe.util.MathMan; -import com.boydti.fawe.util.ReflectionUtils; -import com.boydti.fawe.util.TaskManager; -import com.comphenix.protocol.ProtocolLibrary; -import com.comphenix.protocol.ProtocolManager; -import com.comphenix.protocol.injector.netty.WirePacket; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BlockState; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.WorldCreator; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.world.ChunkLoadEvent; -import org.bukkit.event.world.ChunkUnloadEvent; -import org.bukkit.event.world.WorldInitEvent; -import org.bukkit.plugin.Plugin; - -import java.io.File; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.concurrent.ConcurrentHashMap; - -public abstract class BukkitQueue_0 extends NMSMappedFaweQueue implements Listener { - - protected static boolean PAPER = true; - private static BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); - private static Method methodGetHandle; - - static { - Class classCraftChunk = BukkitReflectionUtils.getCbClass("CraftChunk"); - try { - methodGetHandle = ReflectionUtils.setAccessible(classCraftChunk.getDeclaredMethod("getHandle")); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } - } - - public BukkitQueue_0(final com.sk89q.worldedit.world.World world) { - super(world); - if (!registered) { - registered = true; - Bukkit.getServer().getPluginManager().registerEvents(this, ((FaweBukkit) Fawe.imp()).getPlugin()); - } - } - - public BukkitQueue_0(String world) { - super(world); - if (!registered) { - registered = true; - Bukkit.getServer().getPluginManager().registerEvents(this, ((FaweBukkit) Fawe.imp()).getPlugin()); - } - } - - @Override - public boolean supports(Capability capability) { - switch (capability) { - case CHUNK_PACKETS: - Plugin plib = Bukkit.getPluginManager().getPlugin("ProtocolLib"); - return plib != null && plib.isEnabled(); - } - return super.supports(capability); - } - - @Override - public void sendChunk(FaweChunk fc) { - if (!Fawe.isMainThread()) { - startSet(true); - try { - super.sendChunk(fc); - } finally { - endSet(true); - } - } else super.sendChunk(fc); - } - - @Override - public void sendChunkUpdate(FaweChunk chunk, FawePlayer... players) { - if (supports(Capability.CHUNK_PACKETS)) { - sendChunkUpdatePLIB(chunk, players); - } else { - sendBlockUpdate(chunk, players); - } - } - - public void sendChunkUpdatePLIB(FaweChunk chunk, FawePlayer... players) { - ProtocolManager manager = ProtocolLibrary.getProtocolManager(); - WirePacket packet = null; - int viewDistance = Bukkit.getViewDistance(); - try { - for (FawePlayer fawePlayer : players) { - int cx = chunk.getX(); - int cz = chunk.getZ(); - - Player player = ((BukkitPlayer) fawePlayer).parent; - Location loc = player.getLocation(); - - if (Math.abs((loc.getBlockX() >> 4) - cx) <= viewDistance - && Math.abs((loc.getBlockZ() >> 4) - cz) <= viewDistance) { - if (packet == null) { - byte[] data; - byte[] buffer = new byte[8192]; - if (chunk instanceof LazyFaweChunk) { - chunk = (FaweChunk) chunk.getChunk(); - } - // TODO FIXME - // if (chunk instanceof MCAChunk) { - // data = new MCAChunkPacket((MCAChunk) chunk, true, true, hasSky()).apply(buffer); - // } else { - // data = new FaweChunkPacket(chunk, true, true, hasSky()).apply(buffer); - // } - // packet = new WirePacket(PacketType.Play.Server.MAP_CHUNK, data); - } - manager.sendWirePacket(player, packet); - } - } - } catch (InvocationTargetException e) { - throw new RuntimeException(e); - } - } - - @Override - public boolean queueChunkLoad(int cx, int cz, RunnableVal operation) { - if (PAPER) { - try { - new PaperChunkCallback(getImpWorld(), cx, cz) { - @Override - public void onLoad(Chunk bukkitChunk) { - try { - CHUNK chunk = (CHUNK) methodGetHandle.invoke(bukkitChunk); - try { - operation.run(chunk); - } catch (Throwable e) { - e.printStackTrace(); - } - } catch (Throwable e) { - PAPER = false; - } - } - }; - return true; - } catch (Throwable ignore) { - PAPER = false; - } - } - return super.queueChunkLoad(cx, cz); - } - - public static BukkitImplAdapter getAdapter() { - return adapter; - } - - public static Tag toNative(Object tag) { - BukkitImplAdapter adapter = getAdapter(); - return adapter.toNative(tag); - } - - public static Object fromNative(Tag tag) { - BukkitImplAdapter adapter = getAdapter(); - return adapter.fromNative(tag); - } - - @Override - public File getSaveFolder() { - return new File(Bukkit.getWorldContainer(), getWorldName() + File.separator + "region"); - } - - @Override - public void setFullbright(CHUNKSECTIONS sections) {} - - @Override - public void relight(int x, int y, int z) {} - - @Override - public void relightBlock(int x, int y, int z) {} - - @Override - public void relightSky(int x, int y, int z) {} - - @Override - public boolean removeSectionLighting(SECTION sections, int layer, boolean hasSky) { - return false; - } - - public static void checkVersion(String supported) { - String version = Bukkit.getServer().getClass().getPackage().getName(); - if (!version.contains(supported)) { - throw new IllegalStateException("Unsupported version: " + version + " (supports: " + supported + ")"); - } - } - - protected static boolean registered = false; - protected static boolean disableChunkLoad = false; - - @EventHandler - public static void onWorldLoad(WorldInitEvent event) { - if (disableChunkLoad) { - World world = event.getWorld(); - world.setKeepSpawnInMemory(false); - } - } - - public static ConcurrentHashMap keepLoaded = new ConcurrentHashMap<>(8, 0.9f, 1); - - - @EventHandler - public static void onChunkLoad(ChunkLoadEvent event) { - Chunk chunk = event.getChunk(); - long pair = MathMan.pairInt(chunk.getX(), chunk.getZ()); - keepLoaded.putIfAbsent(pair, Fawe.get().getTimer().getTickStart()); - } - - @EventHandler - public static void onChunkUnload(ChunkUnloadEvent event) { - Chunk chunk = event.getChunk(); - long pair = MathMan.pairInt(chunk.getX(), chunk.getZ()); - Long lastLoad = keepLoaded.get(pair); - if (lastLoad != null) { - if (Fawe.get().getTimer().getTickStart() - lastLoad < 10000) { - event.setCancelled(true); - } else { - keepLoaded.remove(pair); - } - } - } - - @Override - public boolean queueChunkLoad(int cx, int cz) { - if (super.queueChunkLoad(cx, cz)) { - keepLoaded.put(MathMan.pairInt(cx, cz), System.currentTimeMillis()); - return true; - } - return false; - } - - public World createWorld(final WorldCreator creator) { - return TaskManager.IMP.sync(new RunnableVal() { - @Override - public void run(World value) { - disableChunkLoad = true; - this.value = creator.createWorld(); - disableChunkLoad = false; - } - }); - } - - @Override - public World getImpWorld() { - return getWorldName() != null ? Bukkit.getWorld(getWorldName()) : null; - } - - @Override - public void sendChunk(int x, int z, int bitMask) {} - - @Override - public void refreshChunk(FaweChunk fs) { - World world = getWorld(); - if(world != null) { - world.refreshChunk(fs.getX(), fs.getZ()); - } - } - - @Override - public boolean regenerateChunk(World world, int x, int z, BiomeType biome, Long seed) { - if (!keepLoaded.isEmpty()) keepLoaded.remove(MathMan.pairInt(x, z)); - return world.regenerateChunk(x, z); - } - - @Override - public boolean hasSky() { - World world = getWorld(); - return world == null || world.getEnvironment() == World.Environment.NORMAL; - } - - private volatile boolean timingsEnabled; - private static boolean alertTimingsChange = true; - - private static Field fieldTimingsEnabled; - private static Field fieldAsyncCatcherEnabled; - private static Method methodCheck; - static { - try { - fieldAsyncCatcherEnabled = Class.forName("org.spigotmc.AsyncCatcher").getField("enabled"); - fieldAsyncCatcherEnabled.setAccessible(true); - } catch (Throwable ignore) {} - try { - fieldTimingsEnabled = Class.forName("co.aikar.timings.Timings").getDeclaredField("timingsEnabled"); - fieldTimingsEnabled.setAccessible(true); - methodCheck = Class.forName("co.aikar.timings.TimingsManager").getDeclaredMethod("recheckEnabled"); - methodCheck.setAccessible(true); - } catch (Throwable ignore){} - } - - @Override - public void startSet(boolean parallel) { - ChunkListener.physicsFreeze = true; - if (parallel) { - try { - if (fieldAsyncCatcherEnabled != null) { - fieldAsyncCatcherEnabled.set(null, false); - } - if (fieldTimingsEnabled != null) { - timingsEnabled = (boolean) fieldTimingsEnabled.get(null); - if (timingsEnabled) { - if (alertTimingsChange) { - alertTimingsChange = false; - Fawe.debug("Having `parallel-threads` > 1 interferes with the timings."); - } - fieldTimingsEnabled.set(null, false); - methodCheck.invoke(null); - } - } - } catch (Throwable e) { - e.printStackTrace(); - } - } - } - - @Override - public void endSet(boolean parallel) { - ChunkListener.physicsFreeze = false; - if (parallel) { - try { - if (fieldAsyncCatcherEnabled != null) { - fieldAsyncCatcherEnabled.set(null, true); - } - if (fieldTimingsEnabled != null && timingsEnabled) { - fieldTimingsEnabled.set(null, true); - methodCheck.invoke(null); - } - } catch (Throwable e) { - e.printStackTrace(); - } - } - } - - @Override - public void sendBlockUpdate(final FaweChunk chunk, FawePlayer... players) { - if (players.length == 0) { - return; - } - int cx = chunk.getX(); - int cz = chunk.getZ(); - int view = Bukkit.getServer().getViewDistance(); - boolean sendAny = false; - boolean[] send = new boolean[players.length]; - for (int i = 0; i < players.length; i++) { - FawePlayer player = players[i]; - Player bp = ((BukkitPlayer) player).parent; - Location loc = bp.getLocation(); - if (Math.abs((loc.getBlockX() >> 4) - cx) <= view && Math.abs((loc.getBlockZ() >> 4) - cz) <= view) { - sendAny = true; - send[i] = true; - } - } - if (!sendAny) { - return; - } - final World world = getWorld(); - final int bx = cx << 4; - final int bz = cz << 4; - chunk.forEachQueuedBlock(new FaweChunkVisitor() { - @Override - public void run(int localX, int y, int localZ, int combined) { - Location loc = new Location(world, bx + localX, y, bz + localZ); - for (int i = 0; i < players.length; i++) { - if (send[i]) { - ((BukkitPlayer) players[i]).parent.sendBlockChange(loc, BukkitAdapter.adapt(BlockState.getFromInternalId(combined))); - } - } - } - }); - } -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_All.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_All.java deleted file mode 100644 index 7fc632ecb..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_All.java +++ /dev/null @@ -1,403 +0,0 @@ -package com.boydti.fawe.bukkit.v0; - -import com.boydti.fawe.bukkit.util.BukkitReflectionUtils; -import com.boydti.fawe.config.Settings; -import com.boydti.fawe.example.NullRelighter; -import com.boydti.fawe.example.Relighter; -import com.boydti.fawe.object.FaweChunk; -import com.boydti.fawe.object.RegionWrapper; -import com.boydti.fawe.object.RunnableVal; -import com.boydti.fawe.util.MathMan; -import com.boydti.fawe.util.ReflectionUtils; -import com.boydti.fawe.util.SetQueue; -import com.boydti.fawe.util.TaskManager; - -import com.google.common.collect.MapMaker; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockTypes; -import org.bukkit.Chunk; -import org.bukkit.ChunkSnapshot; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.block.Biome; -import org.bukkit.block.data.BlockData; - -import java.io.File; -import java.io.RandomAccessFile; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.ArrayDeque; -import java.util.Map; -import java.util.concurrent.ConcurrentMap; - -public class BukkitQueue_All extends BukkitQueue_0 { - - private ConcurrentMap chunkCache = new MapMaker() - .weakValues() - .makeMap(); - - public BukkitQueue_All(com.sk89q.worldedit.world.World world) { - super(world); - Settings.IMP.QUEUE.PARALLEL_THREADS = 1; - } - - public BukkitQueue_All(String world) { - super(world); - Settings.IMP.QUEUE.PARALLEL_THREADS = 1; - } - - @Override - public boolean queueChunkLoad(int cx, int cz, RunnableVal operation) { - if (PAPER) { - try { - new PaperChunkCallback(getImpWorld(), cx, cz) { - @Override - public void onLoad(Chunk chunk) { - try { - ChunkSnapshot snapshot = tryGetSnasphot(chunk); - operation.run(snapshot); - } catch (Throwable e) { - PAPER = false; - } - } - }; - return true; - } catch (Throwable ignore) { - PAPER = false; - } - } - return super.queueChunkLoad(cx, cz); - } - - @Override - public Relighter getRelighter() { - return NullRelighter.INSTANCE; - } - - private static Class classRegionFileCache; - private static Method methodGetHandleChunk; - private static Method methodGetHandleWorld; - private static Method methodFlush; - private static Method methodNeedsSaving; - private static Field fieldChunkProvider; - private static Field fieldChunkLoader; - private static Field fieldRegionMap; - private static Field fieldRegionRAF; - - static { - try { - BukkitReflectionUtils.init(); - classRegionFileCache = BukkitReflectionUtils.getNmsClass("RegionFileCache"); - Class classRegionFile = BukkitReflectionUtils.getNmsClass("RegionFile"); - Class classCraftChunk = BukkitReflectionUtils.getCbClass("CraftChunk"); - Class classNMSChunk = BukkitReflectionUtils.getNmsClass("Chunk"); - Class classCraftWorld = BukkitReflectionUtils.getCbClass("CraftWorld"); - Class classNMSWorld = BukkitReflectionUtils.getNmsClass("World"); - Class classChunkProviderServer = BukkitReflectionUtils.getNmsClass("ChunkProviderServer"); - Class classIChunkProvider = BukkitReflectionUtils.getNmsClass("IChunkProvider"); - Class classIChunkLoader = BukkitReflectionUtils.getNmsClass("IChunkLoader"); - Class classChunkRegionLoader = BukkitReflectionUtils.getNmsClass("ChunkRegionLoader"); - - methodGetHandleChunk = ReflectionUtils.setAccessible(classCraftChunk.getDeclaredMethod("getHandle")); - methodGetHandleWorld = ReflectionUtils.setAccessible(classCraftWorld.getDeclaredMethod("getHandle")); - methodFlush = ReflectionUtils.findMethod(classChunkRegionLoader, boolean.class); - methodNeedsSaving = ReflectionUtils.findMethod(classNMSChunk, boolean.class, boolean.class); - - fieldChunkProvider = ReflectionUtils.findField(classNMSWorld, classIChunkProvider); - fieldChunkLoader = ReflectionUtils.findField(classChunkProviderServer, classIChunkLoader); - - fieldRegionMap = ReflectionUtils.findField(classRegionFileCache, Map.class); - fieldRegionRAF = ReflectionUtils.findField(classRegionFile, RandomAccessFile.class); - } catch (Throwable throwable) { - throwable.printStackTrace(); - } - } - - @Override - public boolean setMCA(int mcaX, int mcaZ, RegionWrapper allowed, Runnable whileLocked, boolean saveChunks, boolean load) { - if (classRegionFileCache == null) { - return super.setMCA(mcaX, mcaZ, allowed, whileLocked, saveChunks, load); - } - TaskManager.IMP.sync(new RunnableVal() { - @Override - public void run(Boolean value) { - long start = System.currentTimeMillis(); - long last = start; - synchronized (classRegionFileCache) { - try { - World world = getWorld(); - boolean autoSave = world.isAutoSave(); - - if (world.getKeepSpawnInMemory()) world.setKeepSpawnInMemory(false); - - ArrayDeque unloaded = null; - if (load) { - int bcx = mcaX << 5; - int bcz = mcaZ << 5; - int tcx = bcx + 31; - int tcz = bcz + 31; - for (Chunk chunk : world.getLoadedChunks()) { - int cx = chunk.getX(); - int cz = chunk.getZ(); - if (cx >= bcx && cx <= tcx && cz >= bcz && cz <= tcz) { - Object nmsChunk = methodGetHandleChunk.invoke(chunk); - boolean mustSave = saveChunks && (boolean) methodNeedsSaving.invoke(nmsChunk, false); - chunk.unload(mustSave, false); - if (unloaded == null) unloaded = new ArrayDeque<>(); - unloaded.add(chunk); - } - } - } else { - world.save(); - } - - Object nmsWorld = methodGetHandleWorld.invoke(world); - Object chunkProviderServer = fieldChunkProvider.get(nmsWorld); - Object chunkRegionLoader = fieldChunkLoader.get(chunkProviderServer); - while ((boolean) methodFlush.invoke(chunkRegionLoader)); - - if (unloaded != null) { - Map regionMap = (Map) fieldRegionMap.get(null); - File file = new File(world.getWorldFolder(), "region" + File.separator + "r." + mcaX + "." + mcaZ + ".mca"); - Object regionFile = regionMap.remove(file); - if (regionFile != null) { - RandomAccessFile raf = (RandomAccessFile) fieldRegionRAF.get(regionFile); - raf.close(); - } - } - - whileLocked.run(); - - if (load && unloaded != null) { - final ArrayDeque finalUnloaded = unloaded; - TaskManager.IMP.async(() -> { - for (Chunk chunk : finalUnloaded) { - int cx = chunk.getX(); - int cz = chunk.getZ(); - if (world.isChunkLoaded(cx, cz)) continue; - SetQueue.IMP.addTask(() -> { - world.loadChunk(chunk.getX(), chunk.getZ(), false); - world.refreshChunk(chunk.getX(), chunk.getZ()); - }); - - } - }); - // load chunks - - } - } catch (Throwable e) { - e.printStackTrace(); - } - } - } - }); - return true; - } - - @Override - public void setSkyLight(ChunkSnapshot chunk, int x, int y, int z, int value) { - // Not supported - } - - @Override - public void setBlockLight(ChunkSnapshot chunk, int x, int y, int z, int value) { - // Not supported - } - - @Override - public int getCombinedId4Data(ChunkSnapshot chunk, int x, int y, int z) { - if (chunk.isSectionEmpty(y >> 4)) { - return BlockTypes.AIR.getInternalId(); - } - BlockData blockData = chunk.getBlockData(x & 15, y, z & 15); - return BukkitAdapter.adapt(blockData).getInternalId(); - } - - @Override - public BiomeType getBiome(ChunkSnapshot chunkSnapshot, int x, int z) { - Biome biome = chunkSnapshot.getBiome(x & 15, z & 15); - return getAdapter().adapt(biome); - } - - @Override - public ChunkSnapshot getSections(ChunkSnapshot chunkSnapshot) { - return chunkSnapshot; - } - - @Override - public ChunkSnapshot getCachedChunk(World world, int cx, int cz) { - long pair = MathMan.pairInt(cx, cz); - ChunkSnapshot cached = chunkCache.get(pair); - if (cached != null) return cached; - if (world.isChunkLoaded(cx, cz)) { - Long originalKeep = keepLoaded.get(pair); - keepLoaded.put(pair, Long.MAX_VALUE); - if (world.isChunkLoaded(cx, cz)) { - Chunk chunk = world.getChunkAt(cx, cz); - ChunkSnapshot snapshot = getAndCacheChunk(chunk); - if (originalKeep != null) { - keepLoaded.put(pair, originalKeep); - } else { - keepLoaded.remove(pair); - } - return snapshot; - } else { - keepLoaded.remove(pair); - return null; - } - } else { - return null; - } - } - - @Override - public int getEmmittedLight(final ChunkSnapshot chunk, int x, int y, int z) { - return chunk.getBlockEmittedLight(x & 15, y, z & 15); - } - - @Override - public int getSkyLight(final ChunkSnapshot chunk, int x, int y, int z) { - return chunk.getBlockSkyLight(x & 15, y, z & 15); - } - - @Override - public int getLight(final ChunkSnapshot chunk, int x, int y, int z) { - x = x & 15; - z = z & 15; - return Math.max(chunk.getBlockEmittedLight(x, y, z), chunk.getBlockSkyLight(x, y, z)); - } - - @Override - public ChunkSnapshot loadChunk(World world, int x, int z, boolean generate) { - Chunk chunk = world.getChunkAt(x, z); - chunk.load(generate); - return chunk.isLoaded() ? getAndCacheChunk(chunk) : null; - } - - private ChunkSnapshot tryGetSnasphot(Chunk chunk) { - try { - return chunk.getChunkSnapshot(false, true, false); - } catch (Throwable throwable) { - Throwable cause = throwable; - while (cause.getCause() != null) { - cause = cause.getCause(); - } - if (cause instanceof IllegalStateException) { - return null; - } - throw throwable; - } - } - - private ChunkSnapshot getAndCacheChunk(Chunk chunk) { - ChunkSnapshot snapshot = tryGetSnasphot(chunk); - if (snapshot == null) { - snapshot = tryGetSnasphot(chunk); - if (snapshot == null) { - snapshot = TaskManager.IMP.sync(() -> tryGetSnasphot(chunk)); - if (snapshot == null) { - snapshot = chunk.getChunkSnapshot(false, true, false); - } - } - } - chunkCache.put(MathMan.pairInt(chunk.getX(), chunk.getZ()), snapshot); - return snapshot; - } - - @Override - public ChunkSnapshot getCachedSections(World impWorld, int cx, int cz) { - return getCachedChunk(impWorld, cx, cz); - } - - @Override - public CompoundTag getTileEntity(ChunkSnapshot chunk, int x, int y, int z) { - if (getAdapter() == null) { - return null; - } - Location loc = new Location(getWorld(), x, y, z); - BaseBlock block = getAdapter().getBlock(loc); - return block.getNbtData(); - } - - @Override - public FaweChunk getFaweChunk(int x, int z) { - return new BukkitChunk_All(this, x, z); - } - - @Override - public boolean supports(Capability capability) { - switch (capability) { - case CHANGE_TASKS: return getAdapter() != null; - } - return super.supports(capability); - } - - @Override - public void startSet(boolean parallel) { - super.startSet(true); - } - - private Field fieldNeighbors; - private Method chunkGetHandle; - - /** - * Exploiting a bug in the vanilla lighting algorithm for faster block placement - * - Could have been achieved without reflection by force unloading specific chunks - * - Much faster just setting the variable manually though - * @param chunk - * @return - */ - protected Object[] disableLighting(Chunk chunk) { - try { - if (chunkGetHandle == null) { - chunkGetHandle = chunk.getClass().getDeclaredMethod("getHandle"); - chunkGetHandle.setAccessible(true); - } - Object nmsChunk = chunkGetHandle.invoke(chunk); - if (fieldNeighbors == null) { - fieldNeighbors = nmsChunk.getClass().getDeclaredField("neighbors"); - fieldNeighbors.setAccessible(true); - } - Object value = fieldNeighbors.get(nmsChunk); - fieldNeighbors.set(nmsChunk, 0); - return new Object[] {nmsChunk, value}; - } catch (Throwable ignore) {} - return null; - } - - protected void disableLighting(Object[] disableResult) { - if (disableResult != null) { - try { - fieldNeighbors.set(disableResult[0], 0); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - } - } - - protected void resetLighting(Object[] disableResult) { - if (disableResult != null) { - try { - fieldNeighbors.set(disableResult[0], disableResult[1]); - } catch (Throwable throwable) { - throwable.printStackTrace(); - } - } - } - - protected void enableLighting(Object[] disableResult) { - if (disableResult != null) { - try { - fieldNeighbors.set(disableResult[0], 0x739C0); - } catch (Throwable ignore) {} - } - } - - @Override - public void endSet(boolean parallel) { - super.endSet(true); - } -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/PaperChunkCallback.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/PaperChunkCallback.java deleted file mode 100644 index 20592715a..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/PaperChunkCallback.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.boydti.fawe.bukkit.v0; - -import org.bukkit.Chunk; -import org.bukkit.World; - -public abstract class PaperChunkCallback { - public PaperChunkCallback(World world, int x, int z) { - world.getChunkAtAsync(x, z, PaperChunkCallback.this::onLoad); - } - - public abstract void onLoad(Chunk chunk); -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitChunk_1_13.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitChunk_1_13.java deleted file mode 100644 index a023fc927..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitChunk_1_13.java +++ /dev/null @@ -1,627 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13; - -import com.boydti.fawe.Fawe; -import com.boydti.fawe.bukkit.adapter.v1_13_1.BlockMaterial_1_13; -import com.boydti.fawe.bukkit.adapter.v1_13_1.Spigot_v1_13_R2; -import com.boydti.fawe.bukkit.v0.BukkitQueue_0; -import com.boydti.fawe.config.Settings; -import com.boydti.fawe.example.IntFaweChunk; -import com.boydti.fawe.jnbt.anvil.BitArray4096; -import com.boydti.fawe.object.FaweChunk; -import com.boydti.fawe.object.FaweQueue; -import com.boydti.fawe.util.MainUtil; -import com.boydti.fawe.util.MathMan; -import com.boydti.fawe.util.ReflectionUtils; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.LongTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.internal.Constants; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BlockID; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockTypes; -import net.minecraft.server.v1_13_R2.BiomeBase; -import net.minecraft.server.v1_13_R2.Block; -import net.minecraft.server.v1_13_R2.BlockPosition; -import net.minecraft.server.v1_13_R2.Blocks; -import net.minecraft.server.v1_13_R2.ChunkSection; -import net.minecraft.server.v1_13_R2.DataBits; -import net.minecraft.server.v1_13_R2.DataPalette; -import net.minecraft.server.v1_13_R2.DataPaletteBlock; -import net.minecraft.server.v1_13_R2.DataPaletteHash; -import net.minecraft.server.v1_13_R2.DataPaletteLinear; -import net.minecraft.server.v1_13_R2.Entity; -import net.minecraft.server.v1_13_R2.EntityPlayer; -import net.minecraft.server.v1_13_R2.EntityTypes; -import net.minecraft.server.v1_13_R2.GameProfileSerializer; -import net.minecraft.server.v1_13_R2.IBlockData; -import net.minecraft.server.v1_13_R2.MinecraftKey; -import net.minecraft.server.v1_13_R2.NBTTagCompound; -import net.minecraft.server.v1_13_R2.NBTTagInt; -import net.minecraft.server.v1_13_R2.NibbleArray; -import net.minecraft.server.v1_13_R2.RegistryID; -import net.minecraft.server.v1_13_R2.TileEntity; -import org.bukkit.Chunk; -import org.bukkit.World; -import org.bukkit.block.Biome; -import org.bukkit.craftbukkit.v1_13_R2.CraftChunk; -import org.bukkit.craftbukkit.v1_13_R2.block.CraftBlock; -import org.bukkit.event.entity.CreatureSpawnEvent; - -import java.lang.reflect.InvocationTargetException; -import java.util.Collection; -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.UUID; - -import static com.boydti.fawe.bukkit.v0.BukkitQueue_0.getAdapter; -import static com.boydti.fawe.bukkit.v1_13.BukkitQueue_1_13.fieldRegistryb; -import static com.boydti.fawe.bukkit.v1_13.BukkitQueue_1_13.fieldRegistryc; -import static com.boydti.fawe.bukkit.v1_13.BukkitQueue_1_13.fieldRegistryd; -import static com.boydti.fawe.bukkit.v1_13.BukkitQueue_1_13.fieldRegistrye; -import static com.boydti.fawe.bukkit.v1_13.BukkitQueue_1_13.fieldRegistryf; - -public class BukkitChunk_1_13 extends IntFaweChunk { - - public ChunkSection[] sectionPalettes; - - private static final IBlockData AIR = ((BlockMaterial_1_13) BlockTypes.AIR.getMaterial()).getState(); - - /** - * A FaweSections object represents a chunk and the blocks that you wish to change in it. - * - * @param parent - * @param x - * @param z - */ - public BukkitChunk_1_13(FaweQueue parent, int x, int z) { - super(parent, x, z); - } - - public BukkitChunk_1_13(FaweQueue parent, int x, int z, int[][] ids, short[] count, short[] air) { - super(parent, x, z, ids, count, air); - } - - public void storeBiomes(BiomeBase[] biomes) { - if (biomes != null) { - if (this.biomes == null) { - this.biomes = new BiomeType[256]; - } - for (int i = 0; i < 256; i++) { - this.biomes[i] = BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(biomes[i])); - } - } - } - - @Override - public int[][] getCombinedIdArrays() { - if (this.sectionPalettes != null) { - for (int i = 0; i < setBlocks.length; i++) { - getIdArray(i); - } - } - return this.setBlocks; - } - - @Override - public int[] getIdArray(int layer) { - if (this.setBlocks[layer] == null && this.sectionPalettes != null) { - ChunkSection section = this.sectionPalettes[layer]; - int[] idsArray = this.setBlocks[layer]; - if (section != null && idsArray == null) { - this.setBlocks[layer] = idsArray = new int[4096]; - if (!section.a()) { - try { - DataPaletteBlock blocks = section.getBlocks(); - DataBits bits = (DataBits) BukkitQueue_1_13.fieldBits.get(blocks); - DataPalette palette = (DataPalette) BukkitQueue_1_13.fieldPalette.get(blocks); - - long[] raw = bits.a(); - int bitsPerEntry = bits.c(); - - new BitArray4096(raw, bitsPerEntry).toRaw(idsArray); - IBlockData defaultBlock = (IBlockData) BukkitQueue_1_13.fieldDefaultBlock.get(blocks); - // TODO optimize away palette.a - for (int i = 0; i < 4096; i++) { - IBlockData ibd = palette.a(idsArray[i]); - if (ibd == null) { - ibd = defaultBlock; - } - int ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToInt(ibd); - idsArray[i] = BlockTypes.states[ordinal].getInternalId(); - } - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - } - } - } - return this.setBlocks[layer]; - } - - public boolean storeTile(TileEntity tile, BlockPosition pos) { - CompoundTag nativeTag = getParent().getTag(tile); - setTile(pos.getX() & 15, pos.getY(), pos.getZ() & 15, nativeTag); - return true; - } - - public boolean storeEntity(Entity ent) throws InvocationTargetException, IllegalAccessException { - if (ent instanceof EntityPlayer || BukkitQueue_0.getAdapter() == null) { - return false; - } - EntityTypes type = ent.P(); - MinecraftKey id = EntityTypes.getName(type); - if (id != null) { - NBTTagCompound tag = new NBTTagCompound(); - ent.save(tag); // readEntityIntoTag - CompoundTag nativeTag = (CompoundTag) BukkitQueue_0.toNative(tag); - Map map = ReflectionUtils.getMap(nativeTag.getValue()); - map.put("Id", new StringTag(id.toString())); - setEntity(nativeTag); - return true; - } else { - return false; - } - } - - public boolean storeSection(ChunkSection section, int layer) throws IllegalAccessException { - if (sectionPalettes == null) { - // TODO optimize don't copy light - sectionPalettes = new ChunkSection[16]; - } - sectionPalettes[layer] = section; - return true; - } - - public ChunkSection copy(ChunkSection current) throws IllegalAccessException, InvocationTargetException, NoSuchFieldException { - ChunkSection newSection = new ChunkSection(current.getYPosition(), current.getSkyLightArray() != null); - - // Copy light - NibbleArray skyLight = current.getSkyLightArray(); - NibbleArray blockLight = current.getEmittedLightArray(); - - NibbleArray newBlockLight = newSection.getEmittedLightArray(); - NibbleArray newSkyLight = newSection.getSkyLightArray(); - - byte[] newBlockBytes = newBlockLight.asBytes(); - byte[] blockLightBytes = blockLight.asBytes(); - for (int i = 0; i < 2048; i++) newBlockBytes[i] = blockLightBytes[i]; - if (skyLight != null) { - byte[] newSkyBytes = newSkyLight.asBytes(); - byte[] skyLightBytes = skyLight.asBytes(); - for (int i = 0; i < 2048; i++) newSkyBytes[i] = skyLightBytes[i]; - } - - // Copy counters - Object nonEmptyBlockCount = BukkitQueue_1_13.fieldNonEmptyBlockCount.get(current); - BukkitQueue_1_13.fieldNonEmptyBlockCount.set(newSection, nonEmptyBlockCount); - - Object tickingBlockCount = BukkitQueue_1_13.fieldTickingBlockCount.get(current); - BukkitQueue_1_13.fieldTickingBlockCount.set(newSection, tickingBlockCount); - - Object liquidCount = BukkitQueue_1_13.fieldLiquidCount.get(current); - BukkitQueue_1_13.fieldLiquidCount.set(newSection, liquidCount); - - // Copy blocks - DataPaletteBlock blocks = current.getBlocks(); - DataPaletteBlock blocksCopy = copy(blocks); - BukkitQueue_1_13.fieldSection.set(newSection, blocksCopy); - - return newSection; - } - - public DataPaletteBlock copy(DataPaletteBlock current) throws IllegalAccessException, InvocationTargetException, NoSuchFieldException { - // Clone palette - DataPalette currentPalette = (DataPalette) BukkitQueue_1_13.fieldPalette.get(current); - DataPaletteBlock paletteBlock = newDataPaletteBlock(); - int size = BukkitQueue_1_13.fieldSize.getInt(current); - - DataPalette newPalette = currentPalette; - if (currentPalette instanceof DataPaletteHash) { - // TODO optimize resize - newPalette = new DataPaletteHash<>(Block.REGISTRY_ID, size, paletteBlock, GameProfileSerializer::d, GameProfileSerializer::a); - RegistryID currReg = (RegistryID) BukkitQueue_1_13.fieldHashBlocks.get(currentPalette); - RegistryID newReg = (RegistryID) BukkitQueue_1_13.fieldHashBlocks.get(newPalette); - int arrLen = 1 << size; - System.arraycopy(fieldRegistryb.get(currReg), 0, fieldRegistryb.get(newReg), 0, arrLen); - System.arraycopy(fieldRegistryc.get(currReg), 0, fieldRegistryc.get(newReg), 0, arrLen); - System.arraycopy(fieldRegistryd.get(currReg), 0, fieldRegistryd.get(newReg), 0, arrLen); - fieldRegistrye.set(newReg, fieldRegistrye.get(currReg)); - fieldRegistryf.set(newReg, fieldRegistryf.get(currReg)); - } else if (currentPalette instanceof DataPaletteLinear) { - // TODO optimize resize - newPalette = new DataPaletteLinear<>(Block.REGISTRY_ID, size, paletteBlock, GameProfileSerializer::d); - Object[] currArray = ((Object[]) BukkitQueue_1_13.fieldLinearBlocks.get(currentPalette)); - Object[] newArray = ((Object[]) BukkitQueue_1_13.fieldLinearBlocks.get(newPalette)); - BukkitQueue_1_13.fieldLinearIndex.set(newPalette, BukkitQueue_1_13.fieldLinearIndex.get(currentPalette)); - for (int i = 0; i < newArray.length; i++) newArray[i] = currArray[i]; - } - - BukkitQueue_1_13.fieldPalette.set(paletteBlock, newPalette); - // Clone size - BukkitQueue_1_13.fieldSize.set(paletteBlock, size); - // Clone palette - DataBits currentBits = (DataBits) BukkitQueue_1_13.fieldBits.get(current); - DataBits newBits = new DataBits(currentBits.c(), currentBits.b(), currentBits.a().clone()); - BukkitQueue_1_13.fieldBits.set(paletteBlock, newBits); - - // TODO copy only if different - Object defaultBlock = BukkitQueue_1_13.fieldDefaultBlock.get(current); - if (defaultBlock != AIR) { - ReflectionUtils.setFailsafeFieldValue(BukkitQueue_1_13.fieldDefaultBlock, paletteBlock, BukkitQueue_1_13.fieldDefaultBlock.get(current)); - } - - return paletteBlock; - } - - @Override - public IntFaweChunk copy(boolean shallow) { - BukkitChunk_1_13 copy; - if (shallow) { - copy = new BukkitChunk_1_13(getParent(), getX(), getZ(), setBlocks, count, air); - copy.biomes = biomes; - copy.chunk = chunk; - } else { - copy = new BukkitChunk_1_13(getParent(), getX(), getZ(), (int[][]) MainUtil.copyNd(setBlocks), count.clone(), air.clone()); - copy.biomes = biomes != null ? biomes.clone() : null; - copy.chunk = chunk; - } - if (sectionPalettes != null) { - copy.sectionPalettes = new ChunkSection[16]; - try { - for (int i = 0; i < sectionPalettes.length; i++) { - ChunkSection current = sectionPalettes[i]; - if (current == null) { - continue; - } - copy.sectionPalettes[i] = copy(current); - } - } catch (Throwable e) { - e.printStackTrace(); - } - } - return copy; - } - - private DataPaletteBlock newDataPaletteBlock() { - return new DataPaletteBlock<>(ChunkSection.GLOBAL_PALETTE, Block.REGISTRY_ID, GameProfileSerializer::d, GameProfileSerializer::a, Blocks.AIR.getBlockData()); - } - - @Override - public Chunk getNewChunk() { - return getParent().getWorld().getChunkAt(getX(), getZ()); - } - - public void optimize() { - if (sectionPalettes != null) { - return; - } - int[][] arrays = getCombinedIdArrays(); - for (int layer = 0; layer < 16; layer++) { - if (getCount(layer) > 0) { - if (sectionPalettes == null) { - sectionPalettes = new ChunkSection[16]; - } - int[] array = arrays[layer]; - sectionPalettes[layer] = BukkitQueue_1_13.newChunkSection(layer, getParent().hasSky(), array); - } - } - } - - @Override - public void start() { - getChunk().load(true); - } - - private void removeEntity(Entity entity) { - entity.b(false); - entity.die(); - entity.valid = false; - } - - @Override - public FaweChunk call() { - Spigot_v1_13_R2 adapter = (Spigot_v1_13_R2) BukkitQueue_0.getAdapter(); - try { - BukkitChunk_1_13 copy = getParent().getChangeTask() != null ? new BukkitChunk_1_13(getParent(), getX(), getZ()) : null; - final Chunk chunk = this.getChunk(); - final World world = chunk.getWorld(); - Settings settings = getParent().getSettings(); - int bx = this.getX() << 4; - int bz = this.getZ() << 4; - final boolean flag = world.getEnvironment() == World.Environment.NORMAL; - net.minecraft.server.v1_13_R2.Chunk nmsChunk = ((CraftChunk) chunk).getHandle(); - nmsChunk.f(true); // Set Modified - nmsChunk.mustSave = true; - nmsChunk.markDirty(); - net.minecraft.server.v1_13_R2.World nmsWorld = nmsChunk.world; - ChunkSection[] sections = nmsChunk.getSections(); - List[] entities = nmsChunk.getEntitySlices(); - Map tiles = nmsChunk.getTileEntities(); - // Remove entities - HashSet entsToRemove = this.getEntityRemoves(); - if (!entsToRemove.isEmpty()) { - for (Collection ents : entities) { - if (!ents.isEmpty()) { - Iterator iter = ents.iterator(); - while (iter.hasNext()) { - Entity entity = iter.next(); - if (entsToRemove.contains(entity.getUniqueID())) { - if (copy != null) { - copy.storeEntity(entity); - } - iter.remove(); - synchronized (BukkitQueue_0.class) { - removeEntity(entity); - } - } - } - } - } - } - for (int i = 0; i < entities.length; i++) { - int count = this.getCount(i); - if (count == 0 || settings.EXPERIMENTAL.KEEP_ENTITIES_IN_BLOCKS) { - continue; - } else if (count >= 4096) { - Collection ents = entities[i]; - if (!ents.isEmpty()) { - synchronized (BukkitQueue_0.class) { - Iterator iter = ents.iterator(); - while (iter.hasNext()) { - Entity entity = iter.next(); - if (entity instanceof EntityPlayer) { - continue; - } - iter.remove(); - if (copy != null) { - copy.storeEntity(entity); - } - removeEntity(entity); - } - } - } - } else { - Collection ents = entities[i]; - if (!ents.isEmpty()) { - int layerYStart = i << 4; - int layerYEnd = layerYStart + 15; - int[] array = this.getIdArray(i); - if (array == null) continue; - Iterator iter = ents.iterator(); - while (iter.hasNext()) { - Entity entity = iter.next(); - if (entity instanceof EntityPlayer) { - continue; - } - int y = MathMan.roundInt(entity.locY); - if (y > layerYEnd || y < layerYStart) continue; - int x = (MathMan.roundInt(entity.locX) & 15); - int z = (MathMan.roundInt(entity.locZ) & 15); - - int index = (((y & 0xF) << 8) | (z << 4) | x); - if (array[index] != 0) { - if (copy != null) { - copy.storeEntity(entity); - } - iter.remove(); - synchronized (BukkitQueue_0.class) { - removeEntity(entity); - } - } - } - } - } - } - // Set entities - Set entitiesToSpawn = this.getEntities(); - if (!entitiesToSpawn.isEmpty()) { - synchronized (BukkitQueue_0.class) { - for (CompoundTag nativeTag : entitiesToSpawn) { - Map entityTagMap = ReflectionUtils.getMap(nativeTag.getValue()); - StringTag idTag = (StringTag) entityTagMap.get("Id"); - ListTag posTag = (ListTag) entityTagMap.get("Pos"); - ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); - if (idTag == null || posTag == null || rotTag == null) { - Fawe.debug("Unknown entity tag: " + nativeTag); - continue; - } - double x = posTag.getDouble(0); - double y = posTag.getDouble(1); - double z = posTag.getDouble(2); - float yaw = rotTag.getFloat(0); - float pitch = rotTag.getFloat(1); - String id = idTag.getValue(); - Entity entity = EntityTypes.a(nmsWorld, new MinecraftKey(id)); - if (entity != null) { - UUID uuid = entity.getUniqueID(); - entityTagMap.put("UUIDMost", new LongTag(uuid.getMostSignificantBits())); - entityTagMap.put("UUIDLeast", new LongTag(uuid.getLeastSignificantBits())); - NBTTagCompound tag = (NBTTagCompound) BukkitQueue_1_13.fromNative(nativeTag); - for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - entity.f(tag); - entity.setLocation(x, y, z, yaw, pitch); - synchronized (BukkitQueue_0.class) { - nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM); - } - } - } - } - } - // Set blocks - for (int j = 0; j < sections.length; j++) { - int count = this.getCount(j); - if (count == 0) { - continue; - } - int countAir = this.getAir(j); - final int[] array = this.getIdArray(j); - if (array == null) { - continue; - } - ChunkSection section = sections[j]; - if (copy != null) { - if (section != null) { - copy.storeSection(copy(section), j); - } - } - if (section == null) { - if (count == countAir) { - continue; - } - if (this.sectionPalettes != null && this.sectionPalettes[j] != null) { - section = sections[j] = this.sectionPalettes[j]; - continue; - } else { - section = sections[j] = getParent().newChunkSection(j, flag, array); - continue; - } - } else if (count >= 4096 && false) { - if (countAir >= 4096) { - sections[j] = null; - continue; - } - if (this.sectionPalettes != null && this.sectionPalettes[j] != null) { - section = sections[j] = this.sectionPalettes[j]; - continue; - } else { - section = sections[j] = getParent().newChunkSection(j, flag, array); - continue; - } - } - int by = j << 4; - DataPaletteBlock nibble = section.getBlocks(); - int nonEmptyBlockCount = 0; - IBlockData existing; - - for (int y = 0, i = 0; y < 16; y++) { - for (int z = 0; z < 16; z++) { - for (int x= 0; x < 16; x++, i++) { - int combinedId = array[i]; - switch (combinedId) { - case 0: - continue; - case BlockID.AIR: - case BlockID.CAVE_AIR: - case BlockID.VOID_AIR: - existing = nibble.a(x, y, z); - if (!existing.isAir()) { - if (existing.e() > 0) { - getParent().getRelighter().addLightUpdate(bx + x, by + y, bz + z); - } - nonEmptyBlockCount--; - nibble.setBlock(x, y, z, AIR); - } - continue; - default: - existing = nibble.a(x, y, z); - if (!existing.isAir()) { - if (existing.e() > 0) { - getParent().getRelighter().addLightUpdate(bx + x, by + y, bz + z); - } - } else { - nonEmptyBlockCount++; - } - BlockState state = BlockState.getFromInternalId(combinedId); - IBlockData ibd = ((BlockMaterial_1_13) state.getMaterial()).getState(); - nibble.setBlock(x, y, z, ibd); - } - } - } - } - getParent().setCount(0, getParent().getNonEmptyBlockCount(section) + nonEmptyBlockCount, section); - } - - // Trim tiles - HashMap toRemove = null; - if (!tiles.isEmpty()) { - for (Map.Entry tile : tiles.entrySet()) { - BlockPosition pos = tile.getKey(); - int lx = pos.getX() & 15; - int ly = pos.getY(); - int lz = pos.getZ() & 15; - int layer = ly >> 4; - int[] array = this.getIdArray(layer); - if (array == null) { - continue; - } - int index = (((ly & 0xF) << 8) | (lz << 4) | lx); - if (array[index] != 0) { - if (toRemove == null) { - toRemove = new HashMap<>(); - } - if (copy != null) { - copy.storeTile(tile.getValue(), tile.getKey()); - } - toRemove.put(tile.getKey(), tile.getValue()); - } - } - if (toRemove != null) { - synchronized (BukkitQueue_0.class) { - for (Map.Entry entry : toRemove.entrySet()) { - BlockPosition bp = entry.getKey(); - TileEntity tile = entry.getValue(); - nmsWorld.n(bp); - tiles.remove(bp); - tile.z(); - tile.invalidateBlockCache(); - } - } - } - } - - // Set biomes - if (this.biomes != null) { - BiomeBase[] currentBiomes = nmsChunk.getBiomeIndex(); - if (copy != null) { - copy.storeBiomes(currentBiomes); - } - for (int i = 0 ; i < this.biomes.length; i++) { - BiomeType biome = this.biomes[i]; - if (biome != null) { - Biome craftBiome = adapter.adapt(biome); - currentBiomes[i] = CraftBlock.biomeToBiomeBase(craftBiome); - } - } - } - // Set tiles - Map tilesToSpawn = this.getTiles(); - if (!tilesToSpawn.isEmpty()) { - for (Map.Entry entry : tilesToSpawn.entrySet()) { - CompoundTag nativeTag = entry.getValue(); - short blockHash = entry.getKey(); - int x = (blockHash >> 12 & 0xF) + bx; - int y = (blockHash & 0xFF); - int z = (blockHash >> 8 & 0xF) + bz; - BlockPosition pos = new BlockPosition(x, y, z); // Set pos - synchronized (BukkitQueue_0.class) { - TileEntity tileEntity = nmsWorld.getTileEntity(pos); - if (tileEntity != null) { - NBTTagCompound tag = (NBTTagCompound) BukkitQueue_1_13.fromNative(nativeTag); - tag.set("x", new NBTTagInt(x)); - tag.set("y", new NBTTagInt(y)); - tag.set("z", new NBTTagInt(z)); - tileEntity.load(tag); - } - } - } - } - // Change task - if (copy != null) { - getParent().getChangeTask().run(copy, this); - } - } catch (Throwable e) { - e.printStackTrace(); - } - return this; - } -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java deleted file mode 100644 index 9e2a5a4e1..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java +++ /dev/null @@ -1,722 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13; - -import com.boydti.fawe.FaweCache; -import com.boydti.fawe.bukkit.BukkitPlayer; -import com.boydti.fawe.bukkit.adapter.v1_13_1.BlockMaterial_1_13; -import com.boydti.fawe.bukkit.adapter.v1_13_1.Spigot_v1_13_R2; -import com.boydti.fawe.bukkit.v0.BukkitQueue_0; -import com.boydti.fawe.config.Settings; -import com.boydti.fawe.example.IntFaweChunk; -import com.boydti.fawe.jnbt.anvil.BitArray4096; -import com.boydti.fawe.object.FaweChunk; -import com.boydti.fawe.object.FawePlayer; -import com.boydti.fawe.object.RegionWrapper; -import com.boydti.fawe.object.brush.visualization.VisualChunk; -import com.boydti.fawe.object.visitor.FaweChunkVisitor; -import com.boydti.fawe.util.MathMan; -import com.boydti.fawe.util.TaskManager; - -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BlockID; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockTypes; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import net.minecraft.server.v1_13_R2.*; -import org.bukkit.Chunk; -import org.bukkit.World; -import org.bukkit.craftbukkit.v1_13_R2.CraftChunk; -import org.bukkit.craftbukkit.v1_13_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_13_R2.block.CraftBlock; -import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer; - -import java.io.IOException; -import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.Collection; -import java.util.Map; -import java.util.concurrent.atomic.LongAdder; - -public class BukkitQueue_1_13 extends BukkitQueue_0 { - - final static Field fieldBits; - final static Field fieldPalette; - final static Field fieldSize; - - final static Field fieldHashBlocks; - final static Field fieldLinearBlocks; - private final static Field fieldHashIndex; - final static Field fieldRegistryb; - final static Field fieldRegistryc; - final static Field fieldRegistryd; - final static Field fieldRegistrye; - final static Field fieldRegistryf; - - final static Field fieldLinearIndex; - final static Field fieldDefaultBlock; - - private final static Field fieldFluidCount; - final static Field fieldTickingBlockCount; - final static Field fieldNonEmptyBlockCount; - final static Field fieldSection; - final static Field fieldLiquidCount; - private final static ChunkSection emptySection; - - private final static Field fieldDirtyCount; - private final static Field fieldDirtyBits; - - static { - try { - emptySection = new ChunkSection(0, true); - Arrays.fill(emptySection.getSkyLightArray().asBytes(), (byte) 255); - fieldSection = ChunkSection.class.getDeclaredField("blockIds"); - fieldLiquidCount = ChunkSection.class.getDeclaredField("e"); - fieldSection.setAccessible(true); - fieldLiquidCount.setAccessible(true); - - fieldFluidCount = ChunkSection.class.getDeclaredField("e"); - fieldTickingBlockCount = ChunkSection.class.getDeclaredField("tickingBlockCount"); - fieldNonEmptyBlockCount = ChunkSection.class.getDeclaredField("nonEmptyBlockCount"); - fieldFluidCount.setAccessible(true); - fieldTickingBlockCount.setAccessible(true); - fieldNonEmptyBlockCount.setAccessible(true); - - fieldHashBlocks = DataPaletteHash.class.getDeclaredField("b"); - fieldHashBlocks.setAccessible(true); - fieldLinearBlocks = DataPaletteLinear.class.getDeclaredField("b"); - fieldLinearBlocks.setAccessible(true); - - fieldHashIndex = DataPaletteHash.class.getDeclaredField("f"); - fieldHashIndex.setAccessible(true); - - fieldRegistryb = RegistryID.class.getDeclaredField("b"); - fieldRegistryc = RegistryID.class.getDeclaredField("c"); - fieldRegistryd = RegistryID.class.getDeclaredField("d"); - fieldRegistrye = RegistryID.class.getDeclaredField("e"); - fieldRegistryf = RegistryID.class.getDeclaredField("f"); - fieldRegistryb.setAccessible(true); - fieldRegistryc.setAccessible(true); - fieldRegistryd.setAccessible(true); - fieldRegistrye.setAccessible(true); - fieldRegistryf.setAccessible(true); - - fieldLinearIndex = DataPaletteLinear.class.getDeclaredField("f"); - fieldLinearIndex.setAccessible(true); - - fieldDefaultBlock = DataPaletteBlock.class.getDeclaredField("g"); - fieldDefaultBlock.setAccessible(true); - - fieldSize = DataPaletteBlock.class.getDeclaredField("i"); - fieldSize.setAccessible(true); - - fieldBits = DataPaletteBlock.class.getDeclaredField("a"); - fieldBits.setAccessible(true); - - fieldPalette = DataPaletteBlock.class.getDeclaredField("h"); - fieldPalette.setAccessible(true); - - fieldDirtyCount = PlayerChunk.class.getDeclaredField("dirtyCount"); - fieldDirtyBits = PlayerChunk.class.getDeclaredField("h"); - fieldDirtyCount.setAccessible(true); - fieldDirtyBits.setAccessible(true); - - System.out.println("Using adapter: " + getAdapter()); - System.out.println("========================================="); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - public BukkitQueue_1_13(final com.sk89q.worldedit.world.World world) { - super(world); - getImpWorld(); - } - - public BukkitQueue_1_13(final String world) { - super(world); - getImpWorld(); - } - - private boolean save(net.minecraft.server.v1_13_R2.Chunk chunk, ChunkProviderServer cps) { - cps.saveChunk(chunk, false); - chunk.a(false); - return true; - } - - @Override - public ChunkSection[] getSections(net.minecraft.server.v1_13_R2.Chunk chunk) { - return chunk.getSections(); - } - - @Override - public net.minecraft.server.v1_13_R2.Chunk loadChunk(World world, int x, int z, boolean generate) { - ChunkProviderServer provider = ((CraftWorld) world).getHandle().getChunkProvider(); - if (generate) { - return provider.getChunkAt(x, z, true, true); - } else { - return provider.getChunkAt(x, z, true, false); - } - } - - @Override - public ChunkSection[] getCachedSections(World world, int cx, int cz) { - net.minecraft.server.v1_13_R2.Chunk chunk = ((CraftWorld) world).getHandle().getChunkProvider().getChunkAt(cx, cz, false, false); - if (chunk != null) { - return chunk.getSections(); - } - return null; - } - - @Override - public net.minecraft.server.v1_13_R2.Chunk getCachedChunk(World world, int cx, int cz) { - return ((CraftWorld) world).getHandle().getChunkProvider().getChunkAt(cx, cz, false, false); - } - - @Override - public ChunkSection getCachedSection(ChunkSection[] chunkSections, int cy) { - return chunkSections[cy]; - } - - @Override - public void saveChunk(net.minecraft.server.v1_13_R2.Chunk chunk) { - chunk.f(true); // Set Modified - chunk.mustSave = true; - } - - @Override - public boolean regenerateChunk(World world, int x, int z, BiomeType biome, Long seed) { - return super.regenerateChunk(world, x, z, biome, seed); - } - - @Override - public boolean setMCA(final int mcaX, final int mcaZ, final RegionWrapper allowed, final Runnable whileLocked, final boolean saveChunks, final boolean load) { - throw new UnsupportedOperationException("Anvil not implemented yet"); -// TaskManager.IMP.sync(new RunnableVal() { -// @Override -// public void run(Boolean value) { -// long start = System.currentTimeMillis(); -// long last = start; -// synchronized (RegionFileCache.class) { -// World world = getWorld(); -// if (world.getKeepSpawnInMemory()) world.setKeepSpawnInMemory(false); -// ChunkProviderServer provider = nmsWorld.getChunkProvider(); -// -// boolean mustSave = false; -// boolean[][] chunksUnloaded = null; -// { // Unload chunks -// Iterator iter = provider.a().iterator(); -// while (iter.hasNext()) { -// net.minecraft.server.v1_13_R2.Chunk chunk = iter.next(); -// if (chunk.locX >> 5 == mcaX && chunk.locZ >> 5 == mcaZ) { -// boolean isIn = allowed.isInChunk(chunk.locX, chunk.locZ); -// if (isIn) { -// if (!load) { -// mustSave |= saveChunks && save(chunk, provider); -// continue; -// } -// iter.remove(); -// boolean save = saveChunks && chunk.a(false); -// mustSave |= save; -// provider.unloadChunk(chunk, save); -// if (chunksUnloaded == null) { -// chunksUnloaded = new boolean[32][]; -// } -// int relX = chunk.locX & 31; -// boolean[] arr = chunksUnloaded[relX]; -// if (arr == null) { -// arr = chunksUnloaded[relX] = new boolean[32]; -// } -// arr[chunk.locZ & 31] = true; -// } -// } -// } -// } -// if (mustSave) { -// provider.c(); // TODO only the necessary chunks -// } -// -// File unloadedRegion = null; -// if (load && !RegionFileCache.a.isEmpty()) { -// Map map = RegionFileCache.a; -// Iterator> iter = map.entrySet().iterator(); -// String requiredPath = world.getName() + File.separator + "region"; -// while (iter.hasNext()) { -// Map.Entry entry = iter.next(); -// File file = entry.getKey(); -// int[] regPos = MainUtil.regionNameToCoords(file.getPath()); -// if (regPos[0] == mcaX && regPos[1] == mcaZ && file.getPath().contains(requiredPath)) { -// if (file.exists()) { -// unloadedRegion = file; -// RegionFile regionFile = entry.getValue(); -// iter.remove(); -// try { -// regionFile.c(); -// } catch (IOException e) { -// e.printStackTrace(); -// } -// } -// break; -// } -// } -// } -// -// long now = System.currentTimeMillis(); -// if (whileLocked != null) whileLocked.run(); -// if (!load) return; -// -// { // Load the region again -// if (unloadedRegion != null && chunksUnloaded != null && unloadedRegion.exists()) { -// final boolean[][] finalChunksUnloaded = chunksUnloaded; -// TaskManager.IMP.async(() -> { -// int bx = mcaX << 5; -// int bz = mcaZ << 5; -// for (int x = 0; x < finalChunksUnloaded.length; x++) { -// boolean[] arr = finalChunksUnloaded[x]; -// if (arr != null) { -// for (int z = 0; z < arr.length; z++) { -// if (arr[z]) { -// int cx = bx + x; -// int cz = bz + z; -// SetQueue.IMP.addTask(new Runnable() { -// @Override -// public void run() { -// net.minecraft.server.v1_13_R2.Chunk chunk = provider.getChunkAt(cx, cz, null, false); -// if (chunk != null) { -// PlayerChunk pc = getPlayerChunk(nmsWorld, cx, cz); -// if (pc != null) { -// sendChunk(pc, chunk, 0); -// } -// } -// } -// }); -// } -// } -// } -// } -// }); -// } -// } -// } -// } -// }); -// return true; - } - - @Override - public boolean next(int amount, long time) { - return super.next(amount, time); - } - - @Override - public void setSkyLight(ChunkSection section, int x, int y, int z, int value) { - section.getSkyLightArray().a(x & 15, y & 15, z & 15, value); - } - - @Override - public void setBlockLight(ChunkSection section, int x, int y, int z, int value) { - section.getEmittedLightArray().a(x & 15, y & 15, z & 15, value); - } - - @Override - public int getCombinedId4Data(ChunkSection lastSection, int x, int y, int z) { - DataPaletteBlock dataPalette = lastSection.getBlocks(); - IBlockData ibd = dataPalette.a(x & 15, y & 15, z & 15); - int ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToInt(ibd); - return BlockTypes.states[ordinal].getInternalId(); - } - - @Override - public BiomeType getBiome(net.minecraft.server.v1_13_R2.Chunk chunk, int x, int z) { - BiomeBase base = chunk.getBiomeIndex()[((z & 15) << 4) + (x & 15)]; - return getAdapter().adapt(CraftBlock.biomeBaseToBiome(base)); - } - - @Override - public int getOpacity(ChunkSection section, int x, int y, int z) { - DataPaletteBlock dataPalette = section.getBlocks(); - IBlockData ibd = dataPalette.a(x & 15, y & 15, z & 15); - pos.a(x, y, z); - return ibd.b(nmsWorld, pos); - } - - @Override - public int getBrightness(ChunkSection section, int x, int y, int z) { - DataPaletteBlock dataPalette = section.getBlocks(); - IBlockData ibd = dataPalette.a(x & 15, y & 15, z & 15); - return ibd.e(); - } - - @Override - public int getOpacityBrightnessPair(ChunkSection section, int x, int y, int z) { - DataPaletteBlock dataPalette = section.getBlocks(); - IBlockData ibd = dataPalette.a(x & 15, y & 15, z & 15); - pos.a(x, y, z); - int opacity = ibd.b(nmsWorld, pos); - int brightness = ibd.e(); - return MathMan.pair16(brightness, opacity); - } - - @Override - public void sendChunk(int x, int z, int bitMask) { - net.minecraft.server.v1_13_R2.Chunk chunk = getCachedChunk(getWorld(), x, z); - if (chunk != null) { - sendChunk(getPlayerChunk((WorldServer) chunk.getWorld(), chunk.locX, chunk.locZ), chunk, bitMask); - } - } - - @Override - public void sendChunkUpdatePLIB(FaweChunk chunk, FawePlayer... players) { -// PlayerChunkMap playerManager = ((CraftWorld) getWorld()).getHandle().getPlayerChunkMap(); -// ProtocolManager manager = ProtocolLibrary.getProtocolManager(); -// WirePacket packet = null; -// try { -// for (int i = 0; i < players.length; i++) { -// CraftPlayer bukkitPlayer = ((CraftPlayer) ((BukkitPlayer) players[i]).parent); -// EntityPlayer player = bukkitPlayer.getHandle(); -// -// if (playerManager.a(player, chunk.getX(), chunk.getZ())) { -// if (packet == null) { -// byte[] data; -// byte[] buffer = new byte[8192]; -// if (chunk instanceof LazyFaweChunk) { -// chunk = (FaweChunk) chunk.getChunk(); -// } -// if (chunk instanceof MCAChunk) { -// data = new MCAChunkPacket((MCAChunk) chunk, true, true, hasSky()).apply(buffer); -// } else { -// data = new FaweChunkPacket(chunk, true, true, hasSky()).apply(buffer); -// } -// packet = new WirePacket(PacketType.Play.Server.MAP_CHUNK, data); -// } -// manager.sendWirePacket(bukkitPlayer, packet); -// } -// } -// } catch (InvocationTargetException e) { -// throw new RuntimeException(e); -// } - super.sendChunkUpdatePLIB(chunk, players); // TODO remove - } - - @Override - public void sendBlockUpdate(FaweChunk chunk, FawePlayer... players) { - try { - PlayerChunkMap playerManager = ((CraftWorld) getWorld()).getHandle().getPlayerChunkMap(); - boolean watching = false; - boolean[] watchingArr = new boolean[players.length]; - for (int i = 0; i < players.length; i++) { - EntityPlayer player = ((CraftPlayer) ((BukkitPlayer) players[i]).parent).getHandle(); - if (playerManager.a(player, chunk.getX(), chunk.getZ())) { - watchingArr[i] = true; - watching = true; - } - } - if (!watching) return; - final LongAdder size = new LongAdder(); - if (chunk instanceof VisualChunk) { - size.add(((VisualChunk) chunk).size()); - } else if (chunk instanceof IntFaweChunk) { - size.add(((IntFaweChunk) chunk).getTotalCount()); - } else { - chunk.forEachQueuedBlock(new FaweChunkVisitor() { - @Override - public void run(int localX, int y, int localZ, int combined) { - size.add(1); - } - }); - } - if (size.intValue() == 0) return; - PacketPlayOutMultiBlockChange packet = new PacketPlayOutMultiBlockChange(); - ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer(); - final PacketDataSerializer buffer = new PacketDataSerializer(byteBuf); - buffer.writeInt(chunk.getX()); - buffer.writeInt(chunk.getZ()); - buffer.d(size.intValue()); - chunk.forEachQueuedBlock(new FaweChunkVisitor() { - @Override - public void run(int localX, int y, int localZ, int combined) { - short index = (short) (localX << 12 | localZ << 8 | y); - if (combined < 16) combined = 0; - buffer.writeShort(index); - buffer.d(combined); - } - }); - packet.a(buffer); - for (int i = 0; i < players.length; i++) { - if (watchingArr[i]) ((CraftPlayer) ((BukkitPlayer) players[i]).parent).getHandle().playerConnection.sendPacket(packet); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - - @Override - public void refreshChunk(FaweChunk fc) { - sendChunk(fc.getX(), fc.getZ(), fc.getBitMask()); - } - - public void sendPacket(int cx, int cz, Packet packet) { - PlayerChunk chunk = getPlayerChunk(nmsWorld, cx, cz); - if (chunk != null) { - for (EntityPlayer player : chunk.players) { - player.playerConnection.sendPacket(packet); - } - } - } - - private PlayerChunk getPlayerChunk(WorldServer w, int cx, int cz) { - PlayerChunkMap chunkMap = w.getPlayerChunkMap(); - PlayerChunk playerChunk = chunkMap.getChunk(cx, cz); - if (playerChunk == null) { - return null; - } - if (playerChunk.players.isEmpty()) { - return null; - } - return playerChunk; - } - - private boolean sendChunk(PlayerChunk playerChunk, net.minecraft.server.v1_13_R2.Chunk nmsChunk, int mask) { - if (playerChunk == null) { - return false; - } - if (playerChunk.e()) { - ChunkSection[] sections = nmsChunk.getSections(); - for (int layer = 0; layer < 16; layer++) { - if (sections[layer] == null && (mask & (1 << layer)) != 0) { - sections[layer] = new ChunkSection(layer << 4, nmsWorld.worldProvider.g()); - } - } - TaskManager.IMP.sync(() -> { - try { - int dirtyBits = fieldDirtyBits.getInt(playerChunk); - if (dirtyBits == 0) { - ((CraftWorld) getWorld()).getHandle().getPlayerChunkMap().a(playerChunk); - } - if (mask == 0) { - dirtyBits = 65535; - } else { - dirtyBits |= mask; - } - - fieldDirtyBits.set(playerChunk, dirtyBits); - fieldDirtyCount.set(playerChunk, 64); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - return null; - }); - } - return true; - } - - public boolean hasEntities(net.minecraft.server.v1_13_R2.Chunk nmsChunk) { - try { - final Collection[] entities = nmsChunk.entitySlices; - for (Collection slice : entities) { - if (slice != null && !slice.isEmpty()) { - return true; - } - } - } catch (Throwable ignore) {} - return false; - } - - @Override - public boolean removeSectionLighting(ChunkSection section, int layer, boolean sky) { - if (section != null) { - Arrays.fill(section.getEmittedLightArray().asBytes(), (byte) 0); - if (sky) { - byte[] light = section.getSkyLightArray().asBytes(); - if (light != null) { - Arrays.fill(light, (byte) 0); - } - } - return true; - } - return false; - } - - @Override - public void setFullbright(ChunkSection[] sections) { - for (ChunkSection section : sections) { - if (section != null) { - byte[] bytes = section.getSkyLightArray().asBytes(); - Arrays.fill(bytes, (byte) 255); - } - } - } - - @Override - public int getSkyLight(ChunkSection section, int x, int y, int z) { - return section.c(x & 15, y & 15, z & 15); - } - - @Override - public int getEmmittedLight(ChunkSection section, int x, int y, int z) { - return section.d(x & 15, y & 15, z & 15); - } - - @Override - public void relightBlock(int x, int y, int z) { - pos.c(x, y, z); - nmsWorld.c(EnumSkyBlock.BLOCK, pos); - } - - @Override - public void relightSky(int x, int y, int z) { - pos.c(x, y, z); - nmsWorld.c(EnumSkyBlock.SKY, pos); - } - - @Override - public void relight(int x, int y, int z) { - pos.c(x, y, z); - nmsWorld.r(pos); - } - - private WorldServer nmsWorld; - - @Override - public World getImpWorld() { - World world = super.getImpWorld(); - if (world != null) { - this.nmsWorld = ((CraftWorld) world).getHandle(); - return super.getImpWorld(); - } else { - return null; - } - } - - static void setCount(int tickingBlockCount, int nonEmptyBlockCount, ChunkSection section) throws NoSuchFieldException, IllegalAccessException { - fieldFluidCount.set(section, 0); // TODO FIXME - fieldTickingBlockCount.set(section, tickingBlockCount); - fieldNonEmptyBlockCount.set(section, nonEmptyBlockCount); - } - - int getNonEmptyBlockCount(ChunkSection section) throws IllegalAccessException { - return (int) fieldNonEmptyBlockCount.get(section); - } - - public void setPalette(ChunkSection section, DataPaletteBlock palette) throws NoSuchFieldException, IllegalAccessException { - fieldSection.set(section, palette); - Arrays.fill(section.getEmittedLightArray().asBytes(), (byte) 0); - } - - static ChunkSection newChunkSection(int y2, boolean flag, int[] blocks) { - if (blocks == null) { - return new ChunkSection(y2 << 4, flag); - } else { - ChunkSection section = new ChunkSection(y2 << 4, flag); - int[] blockToPalette = FaweCache.BLOCK_TO_PALETTE.get(); - int[] paletteToBlock = FaweCache.PALETTE_TO_BLOCK.get(); - long[] blockstates = FaweCache.BLOCK_STATES.get(); - int[] blocksCopy = FaweCache.SECTION_BLOCKS.get(); - try { - int num_palette = 0; - int air = 0; - for (int i = 0; i < 4096; i++) { - int stateId = blocks[i]; - switch (stateId) { - case 0: - case BlockID.AIR: - case BlockID.CAVE_AIR: - case BlockID.VOID_AIR: - stateId = BlockID.AIR; - air++; - } - int ordinal = BlockState.getFromInternalId(stateId).getOrdinal(); // TODO fixme Remove all use of BlockTypes.BIT_OFFSET so that this conversion isn't necessary - int palette = blockToPalette[ordinal]; - if (palette == Integer.MAX_VALUE) { - blockToPalette[ordinal] = palette = num_palette; - paletteToBlock[num_palette] = ordinal; - num_palette++; - } - blocksCopy[i] = palette; - } - - // BlockStates - int bitsPerEntry = MathMan.log2nlz(num_palette - 1); - if (Settings.IMP.PROTOCOL_SUPPORT_FIX || num_palette != 1) { - bitsPerEntry = Math.max(bitsPerEntry, 4); // Protocol support breaks <4 bits per entry - } else { - bitsPerEntry = Math.max(bitsPerEntry, 1); // For some reason minecraft needs 4096 bits to store 0 entries - } - - int blockBitArrayEnd = (bitsPerEntry * 4096) >> 6; - if (num_palette == 1) { - for (int i = 0; i < blockBitArrayEnd; i++) blockstates[i] = 0; - } else { - BitArray4096 bitArray = new BitArray4096(blockstates, bitsPerEntry); - bitArray.fromRaw(blocksCopy); - } - - // set palette & data bits - DataPaletteBlock dataPaletteBlocks = section.getBlocks(); - // private DataPalette h; - // protected DataBits a; - long[] bits = Arrays.copyOfRange(blockstates, 0, blockBitArrayEnd); - DataBits nmsBits = new DataBits(bitsPerEntry, 4096, bits); - DataPalette palette = new DataPaletteLinear<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::d); - - // set palette - for (int i = 0; i < num_palette; i++) { - int ordinal = paletteToBlock[i]; - blockToPalette[ordinal] = Integer.MAX_VALUE; - BlockState state = BlockTypes.states[ordinal]; - IBlockData ibd = ((BlockMaterial_1_13) state.getMaterial()).getState(); - palette.a(ibd); - } - try { - fieldBits.set(dataPaletteBlocks, nmsBits); - fieldPalette.set(dataPaletteBlocks, palette); - fieldSize.set(dataPaletteBlocks, bitsPerEntry); - setCount(0, 4096 - air, section); - } catch (IllegalAccessException | NoSuchFieldException e) { - throw new RuntimeException(e); - } - - return section; - } catch (Throwable e){ - Arrays.fill(blockToPalette, Integer.MAX_VALUE); - throw e; - } - } - } - - protected BlockPosition.MutableBlockPosition pos = new BlockPosition.MutableBlockPosition(0, 0, 0); - - @Override - public CompoundTag getTileEntity(net.minecraft.server.v1_13_R2.Chunk chunk, int x, int y, int z) { - Map tiles = chunk.getTileEntities(); - pos.c(x, y, z); - TileEntity tile = tiles.get(pos); - return tile != null ? getTag(tile) : null; - } - - CompoundTag getTag(TileEntity tile) { - try { - NBTTagCompound tag = new NBTTagCompound(); - tile.save(tag); // readTagIntoEntity - return (CompoundTag) toNative(tag); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - @Deprecated - public boolean unloadChunk(final String world, final Chunk chunk) { - net.minecraft.server.v1_13_R2.Chunk c = ((CraftChunk) chunk).getHandle(); - c.mustSave = false; - if (chunk.isLoaded()) { - chunk.unload(false); - } - return true; - } - - @Override - public BukkitChunk_1_13 getFaweChunk(int x, int z) { - return new BukkitChunk_1_13(this, x, z); - } -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_14/adapter/BlockMaterial_1_14.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_14/adapter/BlockMaterial_1_14.java new file mode 100644 index 000000000..149d0c3b9 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_14/adapter/BlockMaterial_1_14.java @@ -0,0 +1,151 @@ +package com.boydti.fawe.bukkit.v1_14.adapter; + +import com.sk89q.util.ReflectionUtil; +import com.sk89q.worldedit.world.registry.BlockMaterial; +import net.minecraft.server.v1_14_R1.Block; +import net.minecraft.server.v1_14_R1.EnumPistonReaction; +import net.minecraft.server.v1_14_R1.IBlockData; +import net.minecraft.server.v1_14_R1.ITileEntity; +import net.minecraft.server.v1_14_R1.Material; +import org.bukkit.craftbukkit.v1_14_R1.block.data.CraftBlockData; + +public class BlockMaterial_1_14 implements BlockMaterial { + private final Block block; + private final IBlockData defaultState; + private final Material material; + private final boolean isTranslucent; + private final CraftBlockData craftBlockData; + + public BlockMaterial_1_14(Block block) { + this(block, block.getBlockData()); + } + + public BlockMaterial_1_14(Block block, IBlockData defaultState) { + this.block = block; + this.defaultState = defaultState; + this.material = defaultState.getMaterial(); + this.craftBlockData = CraftBlockData.fromData(defaultState); + this.isTranslucent = ReflectionUtil.getField(Block.class, block, "v"); + } + + public Block getBlock() { + return block; + } + + public IBlockData getState() { + return defaultState; + } + + public CraftBlockData getCraftBlockData() { + return craftBlockData; + } + + public Material getMaterial() { + return material; + } + + @Override + public boolean isAir() { + return defaultState.isAir(); + } + + @Override + public boolean isFullCube() { + return defaultState.g(); + } + + @Override + public boolean isOpaque() { + return material.f(); + } + + @Override + public boolean isPowerSource() { + return defaultState.isPowerSource(); + } + + @Override + public boolean isLiquid() { + return material.isLiquid(); + } + + @Override + public boolean isSolid() { + return material.isBuildable(); + } + + @Override + public float getHardness() { + return block.strength; + } + + @Override + public float getResistance() { + return block.getDurability(); + } + + @Override + public float getSlipperiness() { + return block.m(); + } + + @Override + public int getLightValue() { + return defaultState.h(); + } + + @Override + public int getLightOpacity() { + return isTranslucent() ? 15 : 0; + } + + @Override + public boolean isFragileWhenPushed() { + return material.getPushReaction() == EnumPistonReaction.DESTROY; + } + + @Override + public boolean isUnpushable() { + return material.getPushReaction() == EnumPistonReaction.BLOCK; + } + + @Override + public boolean isTicksRandomly() { + return block.isTicking(defaultState); + } + + @Override + public boolean isMovementBlocker() { + return material.isSolid(); + } + + @Override + public boolean isBurnable() { + return material.isBurnable(); + } + + @Override + public boolean isToolRequired() { + return !material.isAlwaysDestroyable(); + } + + @Override + public boolean isReplacedDuringPlacement() { + return material.isReplaceable(); + } + + @Override + public boolean isTranslucent() { + return isTranslucent; + } + + @Override + public boolean hasContainer() { + return block instanceof ITileEntity; + } + + @Override + public int getMapColor() { + return material.i().rgb; + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_14/adapter/Spigot_v1_14_R1.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_14/adapter/Spigot_v1_14_R1.java new file mode 100644 index 000000000..6aa146a24 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_14/adapter/Spigot_v1_14_R1.java @@ -0,0 +1,629 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.boydti.fawe.bukkit.v1_14.adapter; + +import com.boydti.fawe.Fawe; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Maps; +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.IntArrayTag; +import com.sk89q.jnbt.IntTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.LongArrayTag; +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.blocks.TileEntityBlock; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.bukkit.adapter.CachedBukkitAdapter; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.LazyBaseEntity; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.registry.state.BooleanProperty; +import com.sk89q.worldedit.registry.state.DirectionalProperty; +import com.sk89q.worldedit.registry.state.EnumProperty; +import com.sk89q.worldedit.registry.state.IntegerProperty; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.registry.BlockMaterial; +import net.minecraft.server.v1_14_R1.Block; +import net.minecraft.server.v1_14_R1.BlockPosition; +import net.minecraft.server.v1_14_R1.BlockStateBoolean; +import net.minecraft.server.v1_14_R1.BlockStateDirection; +import net.minecraft.server.v1_14_R1.BlockStateEnum; +import net.minecraft.server.v1_14_R1.BlockStateInteger; +import net.minecraft.server.v1_14_R1.BlockStateList; +import net.minecraft.server.v1_14_R1.Chunk; +import net.minecraft.server.v1_14_R1.ChunkCoordIntPair; +import net.minecraft.server.v1_14_R1.ChunkSection; +import net.minecraft.server.v1_14_R1.Entity; +import net.minecraft.server.v1_14_R1.EntityTypes; +import net.minecraft.server.v1_14_R1.IBlockData; +import net.minecraft.server.v1_14_R1.IBlockState; +import net.minecraft.server.v1_14_R1.INamable; +import net.minecraft.server.v1_14_R1.IRegistry; +import net.minecraft.server.v1_14_R1.MinecraftKey; +import net.minecraft.server.v1_14_R1.NBTBase; +import net.minecraft.server.v1_14_R1.NBTTagByte; +import net.minecraft.server.v1_14_R1.NBTTagByteArray; +import net.minecraft.server.v1_14_R1.NBTTagCompound; +import net.minecraft.server.v1_14_R1.NBTTagDouble; +import net.minecraft.server.v1_14_R1.NBTTagEnd; +import net.minecraft.server.v1_14_R1.NBTTagFloat; +import net.minecraft.server.v1_14_R1.NBTTagInt; +import net.minecraft.server.v1_14_R1.NBTTagIntArray; +import net.minecraft.server.v1_14_R1.NBTTagList; +import net.minecraft.server.v1_14_R1.NBTTagLong; +import net.minecraft.server.v1_14_R1.NBTTagLongArray; +import net.minecraft.server.v1_14_R1.NBTTagShort; +import net.minecraft.server.v1_14_R1.NBTTagString; +import net.minecraft.server.v1_14_R1.PacketPlayOutEntityStatus; +import net.minecraft.server.v1_14_R1.PacketPlayOutTileEntityData; +import net.minecraft.server.v1_14_R1.PlayerChunkMap; +import net.minecraft.server.v1_14_R1.TileEntity; +import net.minecraft.server.v1_14_R1.World; +import net.minecraft.server.v1_14_R1.WorldServer; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_14_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_14_R1.CraftServer; +import org.bukkit.craftbukkit.v1_14_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_14_R1.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.Nullable; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkNotNull; + +public final class Spigot_v1_14_R1 extends CachedBukkitAdapter implements BukkitImplAdapter{ + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final Field nbtListTagListField; + private final Method nbtCreateTagMethod; + + static { + // A simple test + if (!Bukkit.getServer().getClass().getName().endsWith("DummyServer")) CraftServer.class.cast(Bukkit.getServer()); + } + + // ------------------------------------------------------------------------ + // Code that may break between versions of Minecraft + // ------------------------------------------------------------------------ + + public Spigot_v1_14_R1() throws NoSuchFieldException, NoSuchMethodException { + // The list of tags on an NBTTagList + nbtListTagListField = NBTTagList.class.getDeclaredField("list"); + nbtListTagListField.setAccessible(true); + + // The method to create an NBTBase tag given its type ID + nbtCreateTagMethod = NBTBase.class.getDeclaredMethod("createTag", byte.class); + nbtCreateTagMethod.setAccessible(true); + } + + public char[] idbToStateOrdinal; + + private synchronized boolean init() { + if (idbToStateOrdinal != null) return false; + idbToStateOrdinal = new char[Block.REGISTRY_ID.a()]; // size + for (int i = 0; i < idbToStateOrdinal.length; i++) { + BlockState state = BlockTypes.states[i]; + BlockMaterial_1_14 material = (BlockMaterial_1_14) state.getMaterial(); + int id = Block.REGISTRY_ID.getId(material.getState()); + idbToStateOrdinal[id] = state.getOrdinalChar(); + } + return true; + } + + /** + * Read the given NBT data into the given tile entity. + * + * @param tileEntity the tile entity + * @param tag the tag + */ + private static void readTagIntoTileEntity(NBTTagCompound tag, TileEntity tileEntity) { + try { + tileEntity.load(tag); + } catch (Throwable e) { + Fawe.debug("Invalid tag " + tag + " | " + tileEntity); + } + } + + /** + * Write the tile entity's NBT data to the given tag. + * + * @param tileEntity the tile entity + * @param tag the tag + */ + private static void readTileEntityIntoTag(TileEntity tileEntity, NBTTagCompound tag) { + tileEntity.save(tag); + } + + /** + * Get the ID string of the given entity. + * + * @param entity the entity + * @return the entity ID or null if one is not known + */ + @Nullable + private static String getEntityId(Entity entity) { + MinecraftKey minecraftkey = EntityTypes.getName(entity.getBukkitEntity().getHandle().getEntityType()); + return minecraftkey == null ? null : minecraftkey.toString(); + } + + /** + * Create an entity using the given entity ID. + * + * @param id the entity ID + * @param world the world + * @return an entity or null + */ + @Nullable + private static Entity createEntityFromId(String id, World world) { + return EntityTypes.a(id).get().a(world); + } + + /** + * Write the given NBT data into the given entity. + * + * @param entity the entity + * @param tag the tag + */ + private static void readTagIntoEntity(NBTTagCompound tag, Entity entity) { + entity.f(tag); + } + + /** + * Write the entity's NBT data to the given tag. + * + * @param entity the entity + * @param tag the tag + */ + private static void readEntityIntoTag(Entity entity, NBTTagCompound tag) { + entity.save(tag); + } + + @Override + public BlockMaterial getMaterial(BlockType blockType) { + return new BlockMaterial_1_14(getBlock(blockType)); + } + + @Override + public BlockMaterial getMaterial(BlockState state) { + IBlockData bs = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState(); + return new BlockMaterial_1_14(bs.getBlock(), bs); + } + + public Block getBlock(BlockType blockType) { + return IRegistry.BLOCK.get(new MinecraftKey(blockType.getNamespace(), blockType.getResource())); + } + + // ------------------------------------------------------------------------ + // Code that is less likely to break + // ------------------------------------------------------------------------ + + @SuppressWarnings("deprecation") + @Override + public BaseBlock getBlock(Location location) { + checkNotNull(location); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + org.bukkit.block.Block bukkitBlock = location.getBlock(); + BlockState state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); + if (state.getBlockType().getMaterial().hasContainer()) { + //Read the NBT data + TileEntity te = craftWorld.getHandle().getTileEntity(new BlockPosition(x, y, z)); + if (te != null) { + NBTTagCompound tag = new NBTTagCompound(); + readTileEntityIntoTag(te, tag); // Load data + return state.toBaseBlock((CompoundTag) toNative(tag)); + } + } + + return state.toBaseBlock(); + } + + @Override + public boolean isChunkInUse(org.bukkit.Chunk chunk) { + CraftChunk craftChunk = (CraftChunk) chunk; + PlayerChunkMap chunkMap = ((WorldServer) craftChunk.getHandle().getWorld()).getChunkProvider().playerChunkMap; + return chunkMap.visibleChunks.containsKey(ChunkCoordIntPair.pair(chunk.getX(), chunk.getZ())); + } + + @Override + public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) { + CraftChunk craftChunk = (CraftChunk) chunk; + Chunk nmsChunk = craftChunk.getHandle(); + World nmsWorld = nmsChunk.getWorld(); + + IBlockData blockData = ((BlockMaterial_1_14) state.getMaterial()).getState(); + ChunkSection[] sections = nmsChunk.getSections(); + int y4 = y >> 4; + ChunkSection section = sections[y4]; + + IBlockData existing; + if (section == null) { + existing = ((BlockMaterial_1_14) BlockTypes.AIR.getDefaultState().getMaterial()).getState(); + } else { + existing = section.getType(x & 15, y & 15, z & 15); + } + + BlockPosition pos = new BlockPosition(x, y, z); + + nmsChunk.removeTileEntity(pos); // Force delete the old tile entity + + CompoundTag nativeTag = state instanceof BaseBlock ? ((BaseBlock)state).getNbtData() : null; + if (nativeTag != null || existing instanceof TileEntityBlock) { + nmsWorld.setTypeAndData(pos, blockData, 0); + // remove tile + if (nativeTag != null) { + // We will assume that the tile entity was created for us, + // though we do not do this on the Forge version + TileEntity tileEntity = nmsWorld.getTileEntity(pos); + if (tileEntity != null) { + NBTTagCompound tag = (NBTTagCompound) fromNative(nativeTag); + tag.set("x", new NBTTagInt(x)); + tag.set("y", new NBTTagInt(y)); + tag.set("z", new NBTTagInt(z)); + readTagIntoTileEntity(tag, tileEntity); // Load data + } + } + } else { + if (existing == blockData) return true; + if (section == null) { + if (blockData.isAir()) return true; + sections[y4] = section = new ChunkSection(y4 << 4); + } + nmsChunk.setType(pos = new BlockPosition(x, y, z), blockData, false); + } + if (update) { + nmsWorld.getMinecraftWorld().notify(pos, existing, blockData, 0); + } + return true; + } + + @Override + public BaseEntity getEntity(org.bukkit.entity.Entity entity) { + checkNotNull(entity); + + CraftEntity craftEntity = ((CraftEntity) entity); + Entity mcEntity = craftEntity.getHandle(); + + String id = getEntityId(mcEntity); + + if (id != null) { + EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); + Supplier saveTag = new Supplier() { + @Override + public CompoundTag get() { + NBTTagCompound tag = new NBTTagCompound(); + readEntityIntoTag(mcEntity, tag); + return (CompoundTag) toNative(tag); + } + }; + return new LazyBaseEntity(type, saveTag); + } else { + return null; + } + } + + @Nullable + @Override + public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state) { + checkNotNull(location); + checkNotNull(state); + if (state.getType() == com.sk89q.worldedit.world.entity.EntityTypes.PLAYER) return null; + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + WorldServer worldServer = craftWorld.getHandle(); + + Entity createdEntity = createEntityFromId(state.getType().getId(), craftWorld.getHandle()); + + if (createdEntity != null) { + CompoundTag nativeTag = state.getNbtData(); + if (nativeTag != null) { + NBTTagCompound tag = (NBTTagCompound) fromNative(nativeTag); + for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { + tag.remove(name); + } + readTagIntoEntity(tag, createdEntity); + } + + createdEntity.setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + + worldServer.addEntity(createdEntity, SpawnReason.CUSTOM); + return createdEntity.getBukkitEntity(); + } else { + Fawe.debug("Invalid entity " + state.getType().getId()); + return null; + } + } + + @SuppressWarnings("unchecked") + @Override + public Map> getProperties(BlockType blockType) { + Block block; + try { + block = IRegistry.BLOCK.get(new MinecraftKey(blockType.getNamespace(), blockType.getResource())); + } catch (Throwable e) { + e.printStackTrace(); + return Collections.emptyMap(); + } + if (block == null) { + logger.warn("Failed to find properties for " + blockType.getId()); + return Collections.emptyMap(); + } + Map> properties = Maps.newLinkedHashMap(); + BlockStateList blockStateList = block.getStates(); + for (IBlockState state : blockStateList.d()) { + Property property; + if (state instanceof BlockStateBoolean) { + property = new BooleanProperty(state.a(), ImmutableList.copyOf(state.d())); + } else if (state instanceof BlockStateDirection) { + property = new DirectionalProperty(state.a(), + (List) state.d().stream().map(e -> Direction.valueOf(((INamable) e).getName().toUpperCase())).collect(Collectors.toList())); + } else if (state instanceof BlockStateEnum) { + property = new EnumProperty(state.a(), + (List) state.d().stream().map(e -> ((INamable) e).getName()).collect(Collectors.toList())); + } else if (state instanceof BlockStateInteger) { + property = new IntegerProperty(state.a(), ImmutableList.copyOf(state.d())); + } else { + throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName()); + } + + properties.put(property.getName(), property); + } + return properties; + } + + /** + * 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 + */ + @SuppressWarnings("unchecked") + @Override + public Tag toNative(NBTBase foreign) { + if (foreign == null) { + return null; + } + if (foreign instanceof NBTTagCompound) { + Map values = new HashMap<>(); + Set foreignKeys = ((NBTTagCompound) foreign).getKeys(); // map.keySet + + for (String str : foreignKeys) { + NBTBase base = ((NBTTagCompound) foreign).get(str); + values.put(str, toNative(base)); + } + return new CompoundTag(values); + } else if (foreign instanceof NBTTagByte) { + return new ByteTag(((NBTTagByte) foreign).asByte()); + } else if (foreign instanceof NBTTagByteArray) { + return new ByteArrayTag(((NBTTagByteArray) foreign).getBytes()); // data + } else if (foreign instanceof NBTTagDouble) { + return new DoubleTag(((NBTTagDouble) foreign).asDouble()); // getDouble + } else if (foreign instanceof NBTTagFloat) { + return new FloatTag(((NBTTagFloat) foreign).asFloat()); + } else if (foreign instanceof NBTTagInt) { + return new IntTag(((NBTTagInt) foreign).asInt()); + } else if (foreign instanceof NBTTagIntArray) { + return new IntArrayTag(((NBTTagIntArray) foreign).getInts()); // data + } else if (foreign instanceof NBTTagLongArray) { + return new LongArrayTag(((NBTTagLongArray) foreign).getLongs()); // data + } else if (foreign instanceof NBTTagList) { + try { + return toNativeList((NBTTagList) foreign); + } catch (Throwable e) { + logger.warn("Failed to convert NBTTagList", e); + return new ListTag(ByteTag.class, new ArrayList()); + } + } else if (foreign instanceof NBTTagLong) { + return new LongTag(((NBTTagLong) foreign).asLong()); + } else if (foreign instanceof NBTTagShort) { + return new ShortTag(((NBTTagShort) foreign).asShort()); + } else if (foreign instanceof NBTTagString) { + return new StringTag(foreign.asString()); + } else if (foreign instanceof NBTTagEnd) { + return new EndTag(); + } else { + throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); + } + } + + /** + * Convert a foreign NBT list tag into a native WorldEdit one. + * + * @param foreign the foreign tag + * @return the converted tag + * @throws NoSuchFieldException on error + * @throws SecurityException on error + * @throws IllegalArgumentException on error + * @throws IllegalAccessException on error + */ + public ListTag toNativeList(NBTTagList foreign) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + List values = new ArrayList<>(); + int type = foreign.getTypeId(); + + List foreignList; + foreignList = (List) nbtListTagListField.get(foreign); + for (int i = 0; i < foreign.size(); i++) { + NBTBase element = (NBTBase) foreignList.get(i); + values.add(toNative(element)); // List elements shouldn't have names + } + + Class cls = NBTConstants.getClassFromType(type); + return new ListTag(cls, values); + } + + /** + * Converts a WorldEdit-native NBT structure to a NMS structure. + * + * @param foreign structure to convert + * @return non-native structure + */ + @Override + public 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 LongArrayTag) { + return new NBTTagLongArray(((LongArrayTag) 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 { + return (NBTBase) nbtCreateTagMethod.invoke(null, (byte) 0); + } catch (Exception e) { + return null; + } + } else { + throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName()); + } + } + + @Override + public BlockState adapt(BlockData blockData) { + CraftBlockData cbd = ((CraftBlockData) blockData); + IBlockData ibd = cbd.getState(); + return adapt(ibd); + } + + public BlockState adapt(IBlockData ibd) { + return BlockTypes.states[adaptToInt(ibd)]; + } + + public int adaptToInt(IBlockData ibd) { + try { + int id = Block.REGISTRY_ID.getId(ibd); + return idbToStateOrdinal[id]; + } catch (NullPointerException e) { + init(); + return adaptToInt(ibd); + } + } + + public char adaptToChar(IBlockData ibd) { + try { + int id = Block.REGISTRY_ID.getId(ibd); + return idbToStateOrdinal[id]; + } catch (NullPointerException e) { + init(); + return adaptToChar(ibd); + } + } + + @Override + public BlockData adapt(BlockStateHolder state) { + BlockMaterial_1_14 material = (BlockMaterial_1_14) state.getMaterial(); + return material.getCraftBlockData(); + } + + @Override + public void sendFakeNBT(Player player, BlockVector3 pos, CompoundTag nbtData) { + ((CraftPlayer) player).getHandle().playerConnection.sendPacket(new PacketPlayOutTileEntityData( + new BlockPosition(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()), + 7, + (NBTTagCompound) fromNative(nbtData) + )); + } + + @Override + public void notifyAndLightBlock(Location position, BlockState previousType) { + this.setBlock(position.getChunk(), position.getBlockX(), position.getBlockY(), position.getBlockZ(), previousType, true); + } + + @Override + public boolean setBlock(Location location, BlockStateHolder state, boolean notifyAndLight) { + return this.setBlock(location.getChunk(), location.getBlockX(), location.getBlockY(), location.getBlockZ(), state, notifyAndLight); + } + + @Override + public void sendFakeOP(Player player) { + ((CraftPlayer) player).getHandle().playerConnection.sendPacket(new PacketPlayOutEntityStatus( + ((CraftPlayer) player).getHandle(), (byte) 28 + )); + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncBlock.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncBlock.java index 4d0b949cb..23a266da5 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncBlock.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncBlock.java @@ -3,6 +3,7 @@ package com.boydti.fawe.bukkit.wrapper; import com.boydti.fawe.bukkit.wrapper.state.AsyncSign; import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.util.TaskManager; +import com.destroystokyo.paper.block.BlockSoundGroup; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.world.biome.BiomeType; @@ -221,15 +222,26 @@ public class AsyncBlock implements Block { int combined = queue.getCombinedId4Data(x, y, z, 0); BlockType type = BlockTypes.getFromStateId(combined); switch (type.getInternalId()) { - case BlockID.SIGN: - case BlockID.WALL_SIGN: + case BlockID.ACACIA_SIGN: + case BlockID.SPRUCE_SIGN: + case BlockID.ACACIA_WALL_SIGN: + case BlockID.BIRCH_SIGN: + case BlockID.SPRUCE_WALL_SIGN: + case BlockID.BIRCH_WALL_SIGN: + case BlockID.DARK_OAK_SIGN: + case BlockID.DARK_OAK_WALL_SIGN: + case BlockID.JUNGLE_SIGN: + case BlockID.JUNGLE_WALL_SIGN: + case BlockID.OAK_SIGN: + case BlockID.OAK_WALL_SIGN: return new AsyncSign(this, combined); default: return new AsyncBlockState(this, combined); } } - @NotNull @Override + @Override + @NotNull public AsyncBlockState getState(boolean useSnapshot) { return getState(); } @@ -277,7 +289,14 @@ public class AsyncBlock implements Block { @Override public boolean isEmpty() { - return getType().isEmpty(); + switch (getType()) { + case AIR: + case CAVE_AIR: + case VOID_AIR: + return true; + default: + return false; + } } @Override @@ -361,4 +380,9 @@ public class AsyncBlock implements Block { public BoundingBox getBoundingBox() { return this.getUnsafeBlock().getBoundingBox(); } + + @Override + public @NotNull BlockSoundGroup getSoundGroup() { + return TaskManager.IMP.sync(() -> getUnsafeBlock().getSoundGroup()); + } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncChunk.java index 69e9f069c..69da4e4b5 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncChunk.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncChunk.java @@ -11,6 +11,7 @@ import org.bukkit.ChunkSnapshot; import org.bukkit.World; import org.bukkit.block.BlockState; import org.bukkit.entity.Entity; +import org.jetbrains.annotations.NotNull; public class AsyncChunk implements Chunk { @@ -86,16 +87,8 @@ public class AsyncChunk implements Chunk { if (queue instanceof BukkitQueue_0) { BukkitQueue_0 bq = (BukkitQueue_0) queue; if (world.isChunkLoaded(x, z)) { - long pair = MathMan.pairInt(x, z); - Long originalKeep = BukkitQueue_0.keepLoaded.get(pair); - BukkitQueue_0.keepLoaded.put(pair, Long.MAX_VALUE); if (world.isChunkLoaded(x, z)) { task.run(); - if (originalKeep != null) { - BukkitQueue_0.keepLoaded.put(pair, originalKeep); - } else { - BukkitQueue_0.keepLoaded.remove(pair); - } return task.value; } } @@ -130,14 +123,14 @@ public class AsyncChunk implements Chunk { } @Override - public BlockState[] getTileEntities(boolean b) { + public @NotNull BlockState[] getTileEntities(boolean useSnapshot) { if (!isLoaded()) { return new BlockState[0]; } return TaskManager.IMP.sync(new RunnableVal() { @Override public void run(BlockState[] value) { - this.value = world.getChunkAt(x, z).getTileEntities(b); + this.value = world.getChunkAt(x, z).getTileEntities(useSnapshot); } }); } @@ -162,13 +155,8 @@ public class AsyncChunk implements Chunk { return load(false); } - //Do not use the safe variable in this method for compatibility with 1.14+ - public boolean unload(boolean save, boolean safe) { - return world.unloadChunk(x, z, save); - } - public boolean unload(boolean save) { - return unload(true, false); + return world.unloadChunk(x, z, save); } @Override diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java index 47080122f..e263757f4 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java @@ -1,6 +1,6 @@ package com.boydti.fawe.bukkit.wrapper; -import com.avaje.ebean.validation.NotNull; +import com.bekvon.bukkit.residence.commands.material; import com.boydti.fawe.FaweAPI; import com.boydti.fawe.bukkit.v0.BukkitQueue_0; import com.boydti.fawe.object.FaweQueue; @@ -29,6 +29,7 @@ import org.bukkit.*; import org.bukkit.block.Biome; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; +import org.bukkit.entity.AbstractArrow; import org.bukkit.entity.Arrow; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; @@ -47,6 +48,7 @@ import org.bukkit.util.BoundingBox; import org.bukkit.util.Consumer; import org.bukkit.util.RayTraceResult; import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; /** * Modify the world from an async thread
@@ -68,28 +70,6 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue parent.spawnParticle(particle, v, v1, v2, i, v3, v4, v5, v6, t); } - @Override - public Entity getEntity(UUID uuid) { - return TaskManager.IMP.sync(() -> parent.getEntity(uuid)); - } - - - @Override - public boolean createExplosion(Entity source, Location loc, float power, boolean setFire, boolean breakBlocks) { - return TaskManager.IMP.sync(() -> parent.createExplosion(source, loc, power, setFire, breakBlocks)); - } - - - @Override - public void spawnParticle(Particle particle, List receivers, Player source, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, T data) { - parent.spawnParticle(particle, receivers, source, x, y, z, count, offsetX, offsetY, offsetZ, extra, data); - } - - @Override - public void spawnParticle(Particle particle, List list, Player player, double v, double v1, double v2, int i, double v3, double v4, double v5, double v6, T t, boolean b) { - parent.spawnParticle(particle, list, player, v, v1, v2, i, v3, v4, v5, v6, t, b); - } - /** * @deprecated use {@link #wrap(World)} instead * @param parent Parent world @@ -187,15 +167,6 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue } } - public int getHighestBlockYAt(int x, int z, com.destroystokyo.paper.HeightmapType heightmap) throws UnsupportedOperationException { - return TaskManager.IMP.sync(new Supplier() { - @Override - public Integer get() { - return parent.getHighestBlockYAt(x, z, heightmap); - } - }); - } - @Override public WorldBorder getWorldBorder() { return TaskManager.IMP.sync(new RunnableVal() { @@ -322,21 +293,6 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue return parent.isChunkGenerated(x, z); } - @Override - public void getChunkAtAsync(int x, int z, ChunkLoadCallback cb) { - parent.getChunkAtAsync(x, z, cb); - } - - @Override - public void getChunkAtAsync(Location location, ChunkLoadCallback cb) { - parent.getChunkAtAsync(location, cb); - } - - @Override - public void getChunkAtAsync(Block block, ChunkLoadCallback cb) { - parent.getChunkAtAsync(block, cb); - } - @Override public boolean isChunkLoaded(Chunk chunk) { return chunk.isLoaded(); @@ -428,17 +384,11 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue @Override public boolean unloadChunk(int x, int z, boolean save) { - return unloadChunk(x, z, save, false); - } - - @Deprecated - @Override - public boolean unloadChunk(final int x, final int z, final boolean save, final boolean safe) { if (isChunkLoaded(x, z)) { return TaskManager.IMP.sync(new RunnableVal() { @Override public void run(Boolean value) { - this.value = parent.unloadChunk(x, z, save, safe); + this.value = parent.unloadChunk(x, z, save); } }); } @@ -447,12 +397,15 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue @Override public boolean unloadChunkRequest(int x, int z) { - return unloadChunk(x, z); - } - - @Override - public boolean unloadChunkRequest(int x, int z, boolean safe) { - return unloadChunk(x, z, safe); + if (isChunkLoaded(x, z)) { + return TaskManager.IMP.sync(new RunnableVal() { + @Override + public void run(Boolean value) { + this.value = parent.unloadChunkRequest(x, z); + } + }); + } + return true; } @Override @@ -503,8 +456,8 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue } @Override - public T spawnArrow(Location location, Vector vector, float v, float v1, Class aClass) { - return parent.spawnArrow(location, vector, v, v1, aClass); + public @NotNull T spawnArrow(@NotNull Location location, @NotNull Vector direction, float speed, float spread, @NotNull Class clazz) { + return parent.spawnArrow(location, direction, speed, spread, clazz); } @Override @@ -1134,61 +1087,6 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue return adapter; } - @Override - public int getEntityCount() { - return TaskManager.IMP.sync(new RunnableVal() { - @Override - public void run(Integer value) { - this.value = parent.getEntityCount(); - } - }); - } - - @Override - public int getTileEntityCount() { - return TaskManager.IMP.sync(new RunnableVal() { - @Override - public void run(Integer value) { - this.value = parent.getTileEntityCount(); - } - }); - } - - @Override - public int getTickableTileEntityCount() { - return TaskManager.IMP.sync(new RunnableVal() { - @Override - public void run(Integer value) { - this.value = parent.getTickableTileEntityCount(); - } - }); - } - - @Override - public int getChunkCount() { - return TaskManager.IMP.sync(new RunnableVal() { - @Override - public void run(Integer value) { - this.value = parent.getChunkCount(); - } - }); - } - - @Override - public int getPlayerCount() { - return TaskManager.IMP.sync(new RunnableVal() { - @Override - public void run(Integer value) { - this.value = parent.getPlayerCount(); - } - }); - } - - @Override - public CompletableFuture getChunkAtAsync(int arg0, int arg1, boolean arg2) { - return parent.getChunkAtAsync(arg0, arg1, arg2); - } - @Override public Collection getNearbyEntities(BoundingBox arg0) { return parent.getNearbyEntities(arg0); @@ -1210,11 +1108,6 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue return parent.isChunkForceLoaded(arg0, arg1); } - @Override - public boolean isDayTime() { - return parent.isDayTime(); - } - @Override public Location locateNearestStructure(Location arg0, StructureType arg1, int arg2, boolean arg3) { return parent.locateNearestStructure(arg0, arg1, arg2, arg3); @@ -1285,4 +1178,111 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue public Collection getForceLoadedChunks() { return parent.getForceLoadedChunks(); } + + @Override + public int getHighestBlockYAt(int x, int z, com.destroystokyo.paper.HeightmapType heightmap) throws UnsupportedOperationException { + return TaskManager.IMP.sync(new Supplier() { + @Override + public Integer get() { + return parent.getHighestBlockYAt(x, z, heightmap); + } + }); + } + + @Override + public int getEntityCount() { + return TaskManager.IMP.sync(new RunnableVal() { + @Override + public void run(Integer value) { + this.value = parent.getEntityCount(); + } + }); + } + + @Override + public int getTileEntityCount() { + return TaskManager.IMP.sync(new RunnableVal() { + @Override + public void run(Integer value) { + this.value = parent.getTileEntityCount(); + } + }); + } + + @Override + public int getTickableTileEntityCount() { + return TaskManager.IMP.sync(new RunnableVal() { + @Override + public void run(Integer value) { + this.value = parent.getTickableTileEntityCount(); + } + }); + } + + @Override + public int getChunkCount() { + return TaskManager.IMP.sync(new RunnableVal() { + @Override + public void run(Integer value) { + this.value = parent.getChunkCount(); + } + }); + } + + @Override + public int getPlayerCount() { + return TaskManager.IMP.sync(new RunnableVal() { + @Override + public void run(Integer value) { + this.value = parent.getPlayerCount(); + } + }); + } + + @Override + public CompletableFuture getChunkAtAsync(int arg0, int arg1, boolean arg2) { + return parent.getChunkAtAsync(arg0, arg1, arg2); + } + + @Override + public boolean isDayTime() { + return parent.isDayTime(); + } + + @Override + public void getChunkAtAsync(int x, int z, ChunkLoadCallback cb) { + parent.getChunkAtAsync(x, z, cb); + } + + @Override + public void getChunkAtAsync(Location location, ChunkLoadCallback cb) { + parent.getChunkAtAsync(location, cb); + } + + @Override + public void getChunkAtAsync(Block block, ChunkLoadCallback cb) { + parent.getChunkAtAsync(block, cb); + } + + @Override + public Entity getEntity(UUID uuid) { + return TaskManager.IMP.sync(() -> parent.getEntity(uuid)); + } + + + @Override + public boolean createExplosion(Entity source, Location loc, float power, boolean setFire, boolean breakBlocks) { + return TaskManager.IMP.sync(() -> parent.createExplosion(source, loc, power, setFire, breakBlocks)); + } + + + @Override + public void spawnParticle(Particle particle, List receivers, Player source, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, T data) { + parent.spawnParticle(particle, receivers, source, x, y, z, count, offsetX, offsetY, offsetZ, extra, data); + } + + @Override + public void spawnParticle(Particle particle, List list, Player player, double v, double v1, double v2, int i, double v3, double v4, double v5, double v6, T t, boolean b) { + parent.spawnParticle(particle, list, player, v, v1, v2, i, v3, v4, v5, v6, t, b); + } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncDataContainer.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncDataContainer.java new file mode 100644 index 000000000..f5807c7f4 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncDataContainer.java @@ -0,0 +1,114 @@ +package com.boydti.fawe.bukkit.wrapper.state; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Objects; +import java.util.Map.Entry; + +import com.boydti.fawe.FaweCache; +import com.boydti.fawe.util.ReflectionUtils; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.Tag; +import net.minecraft.server.v1_14_R1.NBTBase; +import net.minecraft.server.v1_14_R1.NBTTagCompound; +import org.apache.commons.lang.Validate; +import org.bukkit.NamespacedKey; +import org.bukkit.craftbukkit.v1_14_R1.persistence.CraftPersistentDataAdapterContext; +import org.bukkit.craftbukkit.v1_14_R1.persistence.CraftPersistentDataTypeRegistry; +import org.bukkit.persistence.PersistentDataAdapterContext; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; + +public final class AsyncDataContainer implements PersistentDataContainer { + private final CompoundTag root; + + public AsyncDataContainer(CompoundTag root) { + this.root = root; + } + + private CompoundTag root() { + CompoundTag value = (CompoundTag) root.getValue().get("PublicBukkitValues"); + return value; + } + + private Map get() { + return get(true); + } + + private Map get(boolean create) { + CompoundTag tag = root(); + Map raw; + if (tag == null) { + if (!create) return Collections.emptyMap(); + Map map = ReflectionUtils.getMap(root.getValue()); + map.put("PublicBukkitValues", new CompoundTag(raw = new HashMap<>())); + } else { + raw = ReflectionUtils.getMap(tag.getValue()); + } + return raw; + } + + public void set(NamespacedKey key, PersistentDataType type, Z value) { + Validate.notNull(key, "The provided key for the custom value was null"); + Validate.notNull(type, "The provided type for the custom value was null"); + Validate.notNull(value, "The provided value for the custom value was null"); + get().put(key.toString(), FaweCache.asTag(type.toPrimitive(value, null))); + } + + public boolean has(NamespacedKey key, PersistentDataType type) { + Validate.notNull(key, "The provided key for the custom value was null"); + Validate.notNull(type, "The provided type for the custom value was null"); + Tag value = get(false).get(key.toString()); + if (value == null) return type == null; + return type.getPrimitiveType() == value.getValue().getClass(); + } + + public Z get(NamespacedKey key, PersistentDataType type) { + Validate.notNull(key, "The provided key for the custom value was null"); + Validate.notNull(type, "The provided type for the custom value was null"); + Tag value = get(false).get(key.toString()); + return (Z) value.toRaw(); + } + + public Z getOrDefault(NamespacedKey key, PersistentDataType type, Z defaultValue) { + Z z = this.get(key, type); + return z != null ? z : defaultValue; + } + + public void remove(NamespacedKey key) { + Validate.notNull(key, "The provided key for the custom value was null"); + get(false).remove(key.toString()); + } + + public boolean isEmpty() { + return get(false).isEmpty(); + } + + public PersistentDataAdapterContext getAdapterContext() { + return null; + } + + public boolean equals(Object obj) { + if (!(obj instanceof AsyncDataContainer)) { + return false; + } else { + Map myRawMap = this.getRaw(); + Map theirRawMap = ((AsyncDataContainer)obj).getRaw(); + return Objects.equals(myRawMap, theirRawMap); + } + } + + public Map getRaw() { + return get(false); + } + + public int hashCode() { + return get(false).hashCode(); + } + + public Map serialize() { + return new CompoundTag(get(false)).toRaw(); + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncSign.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncSign.java index 1dfb8ab9d..9525f601f 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncSign.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncSign.java @@ -8,7 +8,13 @@ import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; import java.util.Map; + +import net.minecraft.server.v1_14_R1.TileEntitySign; +import org.bukkit.DyeColor; import org.bukkit.block.Sign; +import org.bukkit.persistence.PersistentDataContainer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class AsyncSign extends AsyncBlockState implements Sign { public AsyncSign(AsyncBlock block, int combined) { @@ -63,4 +69,28 @@ public class AsyncSign extends AsyncBlockState implements Sign { public void setEditable(boolean arg0) { this.isEditable = arg0; } + + @Override + public @NotNull PersistentDataContainer getPersistentDataContainer() { + return new AsyncDataContainer(getNbtData()); + } + + @Override + public @Nullable DyeColor getColor() { + CompoundTag nbt = getNbtData(); + if (nbt != null) { + String color = nbt.getString("Color").toUpperCase(); + if (color != null) return DyeColor.valueOf(color); + } + return DyeColor.BLACK; + } + + @Override + public void setColor(DyeColor color) { + CompoundTag nbt = getNbtData(); + if (nbt != null) { + Map map = ReflectionUtils.getMap(nbt.getValue()); + map.put("Color", new StringTag(color.name().toLowerCase())); + } + } } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitEntity.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitEntity.java index 5ac3b1893..d21ddcd4c 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitEntity.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitEntity.java @@ -34,6 +34,7 @@ import com.sk89q.worldedit.world.entity.EntityTypes; import org.bukkit.entity.EntityType; import java.lang.ref.WeakReference; +import java.util.Locale; import javax.annotation.Nullable; @@ -88,7 +89,7 @@ public class BukkitEntity implements Entity { @Override public com.sk89q.worldedit.world.entity.EntityType getType() { - return EntityTypes.get(type.getName().toUpperCase()); + return EntityTypes.get(type.getName().toUpperCase(Locale.ROOT)); } @Override diff --git a/worldedit-bukkit/src/main/java/org/bstats/bukkit/MetricsLite.java b/worldedit-bukkit/src/main/java/org/bstats/bukkit/MetricsLite.java new file mode 100644 index 000000000..20772b14b --- /dev/null +++ b/worldedit-bukkit/src/main/java/org/bstats/bukkit/MetricsLite.java @@ -0,0 +1,367 @@ +package org.bstats.bukkit; + +import com.boydti.fawe.config.Settings; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.bukkit.plugin.ServicePriority; + +import javax.net.ssl.HttpsURLConnection; +import java.io.*; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Collection; +import java.util.Timer; +import java.util.TimerTask; +import java.util.UUID; +import java.util.logging.Level; +import java.util.zip.GZIPOutputStream; + +/** + * bStats collects some data for plugin authors. + *

+ * Check out https://bStats.org/ to learn more about bStats! + */ +@SuppressWarnings({"WeakerAccess", "unused"}) +public class MetricsLite { + + static { + // You can use the property to disable the check in your test environment + if (System.getProperty("bstats.relocatecheck") == null || !System.getProperty("bstats.relocatecheck").equals("false")) { + // Maven's Relocate is clever and changes strings, too. So we have to use this little "trick" ... :D + final String defaultPackage = new String( + new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'k', 'k', 'i', 't'}); + final String examplePackage = defaultPackage; + // We want to make sure nobody just copy & pastes the example and use the wrong package names + if (MetricsLite.class.getPackage().getName().equals(defaultPackage) || MetricsLite.class.getPackage().getName().equals(examplePackage)) { + throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); + } + } + } + + // The version of this bStats class + public static final int B_STATS_VERSION = 1; + + // The url to which the data is sent + private static final String URL = "https://bStats.org/submitData/bukkit"; + + // Is bStats enabled on this server? + private boolean enabled; + + // Should failed requests be logged? + private static boolean logFailedRequests; + + // Should the sent data be logged? + private static boolean logSentData; + + // Should the response text be logged? + private static boolean logResponseStatusText; + + // The uuid of the server + private static String serverUUID; + + // The plugin + private final Plugin plugin; + + /** + * Class constructor. + * + * @param plugin The plugin which stats should be submitted. + */ + public MetricsLite(Plugin plugin) { + if (plugin == null) { + throw new IllegalArgumentException("Plugin cannot be null!"); + } + this.plugin = plugin; + + // Get the config file + File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); + File configFile = new File(bStatsFolder, "config.yml"); + YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); + + // Check if the config file exists + if (!config.isSet("serverUuid")) { + + // Add default values + config.addDefault("enabled", Settings.IMP.METRICS); + // Every server gets it's unique random id. + config.addDefault("serverUuid", UUID.randomUUID().toString()); + // Should failed request be logged? + config.addDefault("logFailedRequests", false); + // Should the sent data be logged? + config.addDefault("logSentData", false); + // Should the response text be logged? + config.addDefault("logResponseStatusText", false); + + // Inform the server owners about bStats + config.options().header( + "bStats collects some data for plugin authors like how many servers are using their plugins.\n" + + "To honor their work, you should not disable it.\n" + + "This has nearly no effect on the server performance!\n" + + "Check out https://bStats.org/ to learn more :)" + ).copyDefaults(true); + try { + config.save(configFile); + } catch (IOException ignored) { } + } + + // Load the data + serverUUID = config.getString("serverUuid"); + logFailedRequests = config.getBoolean("logFailedRequests", false); + enabled = config.getBoolean("enabled", Settings.IMP.METRICS); + logSentData = config.getBoolean("logSentData", false); + logResponseStatusText = config.getBoolean("logResponseStatusText", false); + if (enabled) { + boolean found = false; + // Search for all other bStats Metrics classes to see if we are the first one + for (Class service : Bukkit.getServicesManager().getKnownServices()) { + try { + service.getField("B_STATS_VERSION"); // Our identifier :) + found = true; // We aren't the first + break; + } catch (NoSuchFieldException ignored) { } + } + // Register our service + Bukkit.getServicesManager().register(MetricsLite.class, this, plugin, ServicePriority.Normal); + if (!found) { + // We are the first! + startSubmitting(); + } + } + } + + /** + * Checks if bStats is enabled. + * + * @return Whether bStats is enabled or not. + */ + public boolean isEnabled() { + return enabled; + } + + /** + * Starts the Scheduler which submits our data every 30 minutes. + */ + private void startSubmitting() { + final Timer timer = new Timer(true); // We use a timer cause the Bukkit scheduler is affected by server lags + timer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + if (!plugin.isEnabled()) { // Plugin was disabled + timer.cancel(); + return; + } + // Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler + // Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;) + Bukkit.getScheduler().runTask(plugin, () -> submitData()); + } + }, 1000 * 60 * 5, 1000 * 60 * 30); + // Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start + // WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted! + // WARNING: Just don't do it! + } + + /** + * Gets the plugin specific data. + * This method is called using Reflection. + * + * @return The plugin specific data. + */ + public JsonObject getPluginData() { + JsonObject data = new JsonObject(); + + String pluginName = plugin.getDescription().getName(); + String pluginVersion = plugin.getDescription().getVersion(); + + data.addProperty("pluginName", pluginName); // Append the name of the plugin + data.addProperty("pluginVersion", pluginVersion); // Append the version of the plugin + data.add("customCharts", new JsonArray()); + + return data; + } + + /** + * Gets the server specific data. + * + * @return The server specific data. + */ + private JsonObject getServerData() { + // Minecraft specific data + int playerAmount; + try { + // Around MC 1.8 the return type was changed to a collection from an array, + // This fixes java.lang.NoSuchMethodError: org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection; + Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers"); + playerAmount = onlinePlayersMethod.getReturnType().equals(Collection.class) + ? ((Collection) onlinePlayersMethod.invoke(Bukkit.getServer())).size() + : ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length; + } catch (Exception e) { + playerAmount = Bukkit.getOnlinePlayers().size(); // Just use the new method if the Reflection failed + } + int onlineMode = Bukkit.getOnlineMode() ? 1 : 0; + String bukkitVersion = Bukkit.getVersion(); + String bukkitName = Bukkit.getName(); + + // OS/Java specific data + String javaVersion = System.getProperty("java.version"); + String osName = System.getProperty("os.name"); + String osArch = System.getProperty("os.arch"); + String osVersion = System.getProperty("os.version"); + int coreCount = Runtime.getRuntime().availableProcessors(); + + JsonObject data = new JsonObject(); + + data.addProperty("serverUUID", serverUUID); + + data.addProperty("playerAmount", playerAmount); + data.addProperty("onlineMode", onlineMode); + data.addProperty("bukkitVersion", bukkitVersion); + data.addProperty("bukkitName", bukkitName); + + data.addProperty("javaVersion", javaVersion); + data.addProperty("osName", osName); + data.addProperty("osArch", osArch); + data.addProperty("osVersion", osVersion); + data.addProperty("coreCount", coreCount); + + return data; + } + + /** + * Collects the data and sends it afterwards. + */ + private void submitData() { + final JsonObject data = getServerData(); + + JsonArray pluginData = new JsonArray(); + // Search for all other bStats Metrics classes to get their plugin data + for (Class service : Bukkit.getServicesManager().getKnownServices()) { + try { + service.getField("B_STATS_VERSION"); // Our identifier :) + + for (RegisteredServiceProvider provider : Bukkit.getServicesManager().getRegistrations(service)) { + try { + Object plugin = provider.getService().getMethod("getPluginData").invoke(provider.getProvider()); + if (plugin instanceof JsonObject) { + pluginData.add((JsonObject) plugin); + } else { // old bstats version compatibility + try { + Class jsonObjectJsonSimple = Class.forName("org.json.simple.JSONObject"); + if (plugin.getClass().isAssignableFrom(jsonObjectJsonSimple)) { + Method jsonStringGetter = jsonObjectJsonSimple.getDeclaredMethod("toJSONString"); + jsonStringGetter.setAccessible(true); + String jsonString = (String) jsonStringGetter.invoke(plugin); + JsonObject object = new JsonParser().parse(jsonString).getAsJsonObject(); + pluginData.add(object); + } + } catch (ClassNotFoundException e) { + // minecraft version 1.14+ + if (logFailedRequests) { + this.plugin.getLogger().log(Level.SEVERE, "Encountered unexpected exception ", e); + } + continue; // continue looping since we cannot do any other thing. + } + } + } catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { + } + } + } catch (NoSuchFieldException ignored) { } + } + + data.add("plugins", pluginData); + + // Create a new thread for the connection to the bStats server + new Thread(new Runnable() { + @Override + public void run() { + try { + // Send the data + sendData(plugin, data); + } catch (Exception e) { + // Something went wrong! :( + if (logFailedRequests) { + plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e); + } + } + } + }).start(); + } + + /** + * Sends the data to the bStats server. + * + * @param plugin Any plugin. It's just used to get a logger instance. + * @param data The data to send. + * @throws Exception If the request failed. + */ + private static void sendData(Plugin plugin, JsonObject data) throws Exception { + if (data == null) { + throw new IllegalArgumentException("Data cannot be null!"); + } + if (Bukkit.isPrimaryThread()) { + throw new IllegalAccessException("This method must not be called from the main thread!"); + } + if (logSentData) { + plugin.getLogger().info("Sending data to bStats: " + data.toString()); + } + HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection(); + + // Compress the data to save bandwidth + byte[] compressedData = compress(data.toString()); + + // Add headers + connection.setRequestMethod("POST"); + connection.addRequestProperty("Accept", "application/json"); + connection.addRequestProperty("Connection", "close"); + connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request + connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); + connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format + connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION); + + // Send data + connection.setDoOutput(true); + DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream()); + outputStream.write(compressedData); + outputStream.flush(); + outputStream.close(); + + InputStream inputStream = connection.getInputStream(); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); + + StringBuilder builder = new StringBuilder(); + String line; + while ((line = bufferedReader.readLine()) != null) { + builder.append(line); + } + bufferedReader.close(); + if (logResponseStatusText) { + plugin.getLogger().info("Sent data to bStats and received response: " + builder.toString()); + } + } + + /** + * Gzips the given String. + * + * @param str The string to gzip. + * @return The gzipped String. + * @throws IOException If the compression failed. + */ + private static byte[] compress(final String str) throws IOException { + if (str == null) { + return null; + } + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + GZIPOutputStream gzip = new GZIPOutputStream(outputStream); + gzip.write(str.getBytes(StandardCharsets.UTF_8)); + gzip.close(); + return outputStream.toByteArray(); + } + +} \ No newline at end of file diff --git a/worldedit-bukkit/src/main/resources/DummyFawe.src b/worldedit-bukkit/src/main/resources/DummyFawe.src index 5fd4b7be3..16854279b 100644 Binary files a/worldedit-bukkit/src/main/resources/DummyFawe.src and b/worldedit-bukkit/src/main/resources/DummyFawe.src differ diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R1$1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R1$1.class deleted file mode 100644 index efa78dacc..000000000 Binary files a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R1$1.class and /dev/null differ diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R1.class deleted file mode 100644 index 9655a35a6..000000000 Binary files a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R1.class and /dev/null differ diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2$1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2$1.class deleted file mode 100644 index 97a809b53..000000000 Binary files a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2$1.class and /dev/null differ diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2_2$1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2_2$1.class deleted file mode 100644 index e294143a7..000000000 Binary files a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2_2$1.class and /dev/null differ diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2_2.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2_2.class deleted file mode 100644 index 5377fe96c..000000000 Binary files a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2_2.class and /dev/null differ diff --git a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/LazyBlock.java b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/LazyBlock.java deleted file mode 100644 index d87e7c571..000000000 --- a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/LazyBlock.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.blocks; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; -import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.math.BlockVector3; - -/** - * 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 BlockVector3 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(BlockType type, Extent extent, BlockVector3 position) { - super(type); - checkNotNull(extent); - checkNotNull(position); - this.extent = extent; - this.position = position; - } - - /** - * Create a new lazy block. - * - * @param state the block state - * @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(BlockState state, Extent extent, BlockVector3 position) { - super(state); - checkNotNull(extent); - checkNotNull(position); - this.extent = extent; - this.position = position; - } - - @Override - public CompoundTag getNbtData() { - if (!loaded) { - BaseBlock loadedBlock = extent.getFullBlock(position); - this.nbtData = loadedBlock.getNbtData(); - loaded = true; - } - return super.getNbtData(); - } - - @Override - public void setNbtData(CompoundTag nbtData) { - throw new UnsupportedOperationException("This object is immutable"); - } - -} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java b/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java index fb751c22b..d9fe50c22 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java @@ -1,5 +1,6 @@ package com.boydti.fawe; +import com.boydti.fawe.beta.implementation.QueueHandler; import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.Commands; import com.boydti.fawe.config.Settings; @@ -30,22 +31,22 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * [ WorldEdit action] - * | + * | * \|/ * [ EditSession ] - The change is processed (area restrictions, change limit, block type) - * | + * | * \|/ * [Block change] - A block change from some location - * | + * | * \|/ * [ Set Queue ] - The SetQueue manages the implementation specific queue - * | + * | * \|/ * [ Fawe Queue] - A queue of chunks - check if the queue has the chunk for a change - * | + * | * \|/ * [ Fawe Chunk Implementation ] - Otherwise create a new FaweChunk object which is a wrapper around the Chunk object - * | + * | * \|/ * [ Execution ] - When done, the queue then sets the blocks for the chunk, performs lighting updates and sends the chunk packet to the clients *

@@ -81,6 +82,8 @@ public class Fawe { private DefaultTransformParser transformParser; private ChatManager chatManager = new PlainChatManager(); + private QueueHandler queueHandler; + /** * Get the implementation specific class * @@ -175,6 +178,11 @@ public class Fawe { WEManager.IMP.managers.add(new PlotSquaredFeature()); Fawe.debug("Plugin 'PlotSquared' found. Using it now."); } catch (Throwable ignored) {} + try { + imp().startMetrics(); + } catch (Throwable ignored) { + debug(ignored.getMessage()); + } }, 0); TaskManager.IMP.repeat(timer, 1); @@ -183,6 +191,17 @@ public class Fawe { public void onDisable() { } + public QueueHandler getQueueHandler() { + if (queueHandler == null) { + synchronized (this) { + if (queueHandler == null) { + queueHandler = IMP.getQueueHandler(); + } + } + } + return queueHandler; + } + public ChatManager getChatManager() { return chatManager; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/FaweAPI.java b/worldedit-core/src/main/java/com/boydti/fawe/FaweAPI.java index 348aaa0be..0b6e852b5 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/FaweAPI.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/FaweAPI.java @@ -8,6 +8,7 @@ import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.object.RegionWrapper; import com.boydti.fawe.object.changeset.DiskStorageHistory; +import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.object.schematic.Schematic; import com.boydti.fawe.regions.FaweMaskManager; import com.boydti.fawe.util.EditSessionBuilder; @@ -17,6 +18,7 @@ import com.boydti.fawe.util.SetQueue; import com.boydti.fawe.util.TaskManager; import com.boydti.fawe.util.WEManager; import com.boydti.fawe.wrappers.WorldWrapper; + import com.google.common.collect.Sets; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEdit; @@ -36,24 +38,18 @@ import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.world.AbstractWorld; import com.sk89q.worldedit.world.World; -import org.jetbrains.annotations.NotNull; +import javax.annotation.Nullable; import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.net.URL; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.UUID; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; /** * The FaweAPI class offers a few useful functions.
@@ -262,7 +258,7 @@ public class FaweAPI { */ public static void cancelEdit(Extent extent, BBC reason) { try { - WEManager.IMP.cancelEdit(extent, reason); + WEManager.IMP.cancelEdit(extent, new FaweException(reason)); } catch (WorldEditException ignore) { } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java b/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java index c3ed20bf8..9a8420c71 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java @@ -1,14 +1,47 @@ package com.boydti.fawe; +import com.boydti.fawe.beta.Trimable; +import com.boydti.fawe.config.Settings; +import com.boydti.fawe.jnbt.anvil.BitArray4096; import com.boydti.fawe.object.collection.IterableThreadLocal; +import com.boydti.fawe.util.MathMan; import com.sk89q.jnbt.*; +import com.sk89q.worldedit.math.MutableBlockVector3; +import com.sk89q.worldedit.math.MutableVector3; import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; import java.lang.reflect.Field; import java.util.*; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public class FaweCache implements Trimable { + public static final char[] EMPTY_CHAR_4096 = new char[4096]; + + /* + Palette buffers / cache + */ + + @Override + public boolean trim(boolean aggressive) { + BLOCK_TO_PALETTE.clean(); + PALETTE_TO_BLOCK.clean(); + BLOCK_STATES.clean(); + SECTION_BLOCKS.clean(); + PALETTE_CACHE.clean(); + PALETTE_TO_BLOCK_CHAR.clean(); + + MUTABLE_VECTOR3.clean(); + MUTABLE_BLOCKVECTOR3.clean(); + return false; + } -public class FaweCache { public static final IterableThreadLocal BLOCK_TO_PALETTE = new IterableThreadLocal() { @Override public int[] init() { @@ -21,7 +54,16 @@ public class FaweCache { public static final IterableThreadLocal PALETTE_TO_BLOCK = new IterableThreadLocal() { @Override public int[] init() { - return new int[Character.MAX_VALUE]; + return new int[Character.MAX_VALUE + 1]; + } + }; + + public static final IterableThreadLocal PALETTE_TO_BLOCK_CHAR = new IterableThreadLocal() { + @Override + public char[] init() { + char[] result = new char[Character.MAX_VALUE + 1]; + Arrays.fill(result, Character.MAX_VALUE); + return result; } }; @@ -39,6 +81,141 @@ public class FaweCache { } }; + /** + * Holds data for a palette used in a chunk section + */ + public static final class Palette { + public int paletteToBlockLength; + /** + * Reusable buffer array, MUST check paletteToBlockLength for actual length + */ + public int[] paletteToBlock; + + public int blockstatesLength; + /** + * Reusable buffer array, MUST check blockstatesLength for actual length + */ + public long[] blockstates; + } + + private static final IterableThreadLocal PALETTE_CACHE = new IterableThreadLocal() { + @Override + public Palette init() { + return new Palette(); + } + }; + + /** + * Convert raw char array to palette + * @param layerOffset + * @param blocks + * @return palette + */ + public static Palette toPalette(int layerOffset, char[] blocks) { + return toPalette(layerOffset, null, blocks); + } + + /** + * Convert raw int array to palette + * @param layerOffset + * @param blocks + * @return palette + */ + public static Palette toPalette(int layerOffset, int[] blocks) { + return toPalette(layerOffset, blocks, null); + } + + private static Palette toPalette(int layerOffset, int[] blocksInts, char[] blocksChars) { + int[] blockToPalette = BLOCK_TO_PALETTE.get(); + int[] paletteToBlock = PALETTE_TO_BLOCK.get(); + long[] blockstates = BLOCK_STATES.get(); + int[] blocksCopy = SECTION_BLOCKS.get(); + + int blockIndexStart = layerOffset << 12; + int blockIndexEnd = blockIndexStart + 4096; + int num_palette = 0; + try { + if (blocksChars != null) { + for (int i = blockIndexStart, j = 0; i < blockIndexEnd; i++, j++) { + int ordinal = blocksChars[i]; + int palette = blockToPalette[ordinal]; + if (palette == Integer.MAX_VALUE) { +// BlockState state = BlockTypes.states[ordinal]; + blockToPalette[ordinal] = palette = num_palette; + paletteToBlock[num_palette] = ordinal; + num_palette++; + } + blocksCopy[j] = palette; + } + } else if (blocksInts != null) { + for (int i = blockIndexStart, j = 0; i < blockIndexEnd; i++, j++) { + int ordinal = blocksInts[i]; + int palette = blockToPalette[ordinal]; + if (palette == Integer.MAX_VALUE) { + BlockState state = BlockTypes.states[ordinal]; + blockToPalette[ordinal] = palette = num_palette; + paletteToBlock[num_palette] = ordinal; + num_palette++; + } + blocksCopy[j] = palette; + } + } else { + throw new IllegalArgumentException(); + } + + for (int i = 0; i < num_palette; i++) { + blockToPalette[paletteToBlock[i]] = Integer.MAX_VALUE; + } + + // BlockStates + int bitsPerEntry = MathMan.log2nlz(num_palette - 1); + int blockBitArrayEnd = (bitsPerEntry * 4096) >> 6; + if (num_palette == 1) { + // Set a value, because minecraft needs it for some reason + blockstates[0] = 0; + blockBitArrayEnd = 1; + } else { + BitArray4096 bitArray = new BitArray4096(blockstates, bitsPerEntry); + bitArray.fromRaw(blocksCopy); + } + + // Construct palette + Palette palette = PALETTE_CACHE.get(); + palette.paletteToBlockLength = num_palette; + palette.paletteToBlock = paletteToBlock; + + palette.blockstatesLength = blockBitArrayEnd; + palette.blockstates = blockstates; + + return palette; + } catch (Throwable e) { + Arrays.fill(blockToPalette, Integer.MAX_VALUE); + e.printStackTrace(); + throw e; + } + } + + /* + * Vector cache + */ + + public static IterableThreadLocal MUTABLE_BLOCKVECTOR3 = new IterableThreadLocal() { + @Override + public MutableBlockVector3 init() { + return new MutableBlockVector3(); + } + }; + + public static IterableThreadLocal MUTABLE_VECTOR3 = new IterableThreadLocal() { + @Override + public MutableVector3 init() { + return new MutableVector3(); + } + }; + + /* + Conversion methods between JNBT tags and raw values + */ public static Map asMap(Object... pairs) { HashMap map = new HashMap<>(pairs.length >> 1); for (int i = 0; i < pairs.length; i += 2) { @@ -115,7 +292,7 @@ public class FaweCache { } else if (value instanceof String) { return asTag((String) value); } else if (value instanceof Map) { - return asTag((Map) value); + return asTag((Map) value); } else if (value instanceof Collection) { return asTag((Collection) value); } else if (value instanceof Object[]) { @@ -153,7 +330,7 @@ public class FaweCache { } public static ListTag asTag(Object... values) { - Class clazz = null; + Class clazz = null; List list = new ArrayList<>(values.length); for (Object value : values) { Tag tag = asTag(value); @@ -167,7 +344,7 @@ public class FaweCache { } public static ListTag asTag(Collection values) { - Class clazz = null; + Class clazz = null; List list = new ArrayList<>(values.size()); for (Object value : values) { Tag tag = asTag(value); @@ -179,4 +356,16 @@ public class FaweCache { if (clazz == null) clazz = EndTag.class; return new ListTag(clazz, list); } + + /* + Thread stuff + */ + public static ThreadPoolExecutor newBlockingExecutor() { + int nThreads = Settings.IMP.QUEUE.PARALLEL_THREADS; + ArrayBlockingQueue queue = new ArrayBlockingQueue<>(nThreads); + return new ThreadPoolExecutor(nThreads, nThreads, + 0L, TimeUnit.MILLISECONDS, queue + , Executors.defaultThreadFactory(), + new ThreadPoolExecutor.CallerRunsPolicy()); + } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/FaweVersion.java b/worldedit-core/src/main/java/com/boydti/fawe/FaweVersion.java index ae9c913f3..04c334ef3 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/FaweVersion.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/FaweVersion.java @@ -32,9 +32,9 @@ public class FaweVersion { @Override public String toString() { if (hash == 0 && build == 0) { - return "FastAsyncWorldEdit-1.13-NoVer-SNAPSHOT"; + return "FastAsyncWorldEdit-1.14-NoVer-SNAPSHOT"; } else { - return "FastAsyncWorldEdit-1.13" + build; + return "FastAsyncWorldEdit-1.14" + build; } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/IFawe.java b/worldedit-core/src/main/java/com/boydti/fawe/IFawe.java index 304d9d1cb..1f7310186 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/IFawe.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/IFawe.java @@ -1,5 +1,6 @@ package com.boydti.fawe; +import com.boydti.fawe.beta.implementation.QueueHandler; import com.boydti.fawe.object.FaweCommand; import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.FaweQueue; @@ -57,4 +58,6 @@ public interface IFawe { return ""; } + QueueHandler getQueueHandler(); + } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/ArrayFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/ArrayFilterBlock.java new file mode 100644 index 000000000..8e29eecd2 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/ArrayFilterBlock.java @@ -0,0 +1,89 @@ +package com.boydti.fawe.beta; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; + +import javax.annotation.Nullable; + +public class ArrayFilterBlock extends SimpleFilterBlock { + private final char[] blocks; + private final byte[] heights; + private final int yOffset; + private int x, z, index; + private char ordinal; + private final int width, length; + + public ArrayFilterBlock(Extent extent, char[] blocks, byte[] heights, int width, int length, int yOffset) { + super(extent); + this.blocks = blocks; + this.width = width; + this.length = length; + this.heights = heights; + this.yOffset = yOffset; + } + + public void filter2D(Filter filter) { + for (z = 0; z < length; z++) { + for (x = 0; x < width; x++, index++) { + ordinal = blocks[ordinal]; + filter.applyBlock(this); + } + } + } + + @Override + public void setOrdinal(int ordinal) { + blocks[index] = (char) ordinal; + } + + @Override + public void setBlock(BlockState state) { + blocks[index] = state.getOrdinalChar(); + } + + @Override + public void setFullBlock(BaseBlock block) { + blocks[index] = block.getOrdinalChar(); + } + + @Override + public int getOrdinal() { + return ordinal; + } + + @Override + public BlockState getBlock() { + return BlockTypes.states[ordinal]; + } + + @Override + public BaseBlock getFullBlock() { + return getBlock().toBaseBlock(); + } + + @Override + public CompoundTag getNbtData() { + return null; + } + + @Override + public void setNbtData(@Nullable CompoundTag nbtData) {} + + @Override + public int getX() { + return x; + } + + @Override + public int getY() { + return (heights[index] & 0xFF) + yOffset; + } + + @Override + public int getZ() { + return z; + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java new file mode 100644 index 000000000..b1d6589c9 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java @@ -0,0 +1,418 @@ +package com.boydti.fawe.beta; + +import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.registry.BlockMaterial; + +import javax.annotation.Nullable; + +import static com.sk89q.worldedit.world.block.BlockTypes.states; +public class CharFilterBlock extends ChunkFilterBlock { + private CharGetBlocks get; + private IChunkSet set; + + private char[] getArr; + private @Nullable char[] setArr; + private SetDelegate delegate; + + // local + private int layer, index, x, y, z, xx, yy, zz, X, Z; + + public CharFilterBlock(IQueueExtent queueExtent) { + super(queueExtent); + } + + @Override + public final ChunkFilterBlock init(final int X, final int Z, final IChunkGet chunk) { + this.get = (CharGetBlocks) chunk; + this.X = X; + this.Z = Z; + this.xx = X << 4; + this.zz = Z << 4; + return this; + } + + public void flood(final IChunkGet iget, final IChunkSet iset, final int layer, Flood flood, FilterBlockMask mask) { + final int maxDepth = flood.getMaxDepth(); + final boolean checkDepth = maxDepth < Character.MAX_VALUE; + if (init(iget, iset, layer) != null) { + while ((index = flood.poll()) != -1) { + x = index & 15; + z = (index >> 4) & 15; + y = (index >> 8) & 15; + + if (mask.applyBlock(this)) { + int depth = index >> 12; + + if (checkDepth && depth > maxDepth) { + continue; + } + + flood.apply(x, y, z, depth); + } + } + } + } + + @Override + public final ChunkFilterBlock init(final IChunkGet iget, final IChunkSet iset, final int layer) { + this.layer = layer; + final CharGetBlocks get = (CharGetBlocks) iget; + if (!get.hasSection(layer)) return null; + this.set = iset; + getArr = get.sections[layer].get(get, layer); + if (set.hasSection(layer)) { + setArr = set.getArray(layer); + delegate = FULL; + } else { + delegate = NULL; + setArr = null; + } + this.yy = layer << 4; + return this; + } + + @Override + public void filter(Filter filter, int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + this.index = x | (z << 4) | (y << 8); + filter.applyBlock(this); + } + + @Override + public void filter(Filter filter, int yStart, int yEnd) { + for (y = yStart, index = (yStart << 8); y < yEnd; y++) { + for (z = 0; z < 16; z++) { + for (x = 0; x < 16; x++, index++) { + filter.applyBlock(this); + } + } + } + } + + @Override + public void filter(Filter filter, int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { + int yis = (minY << 8); + int zis = (minZ << 4); + for (y = minY, index = yis; y <= maxY; y++) { + for (z = minZ, index += zis; z <= maxZ; z++) { + for (x = minX, index += minX; x <= maxX; x++, index++) { + filter.applyBlock(this); + } + } + } + } + + @Override + public final void filter(final Filter filter, final Region region) { + for (y = 0, index = 0; y < 16; y++) { + int absY = yy + y; + for (z = 0; z < 16; z++) { + int absZ = zz + z; + for (x = 0; x < 16; x++, index++) { + int absX = xx + x; + if (region.contains(absX, absY, absZ)) { + filter.applyBlock(this); + } + } + } + } + } + + @Override + public final void filter(final Filter filter) { + for (y = 0, index = 0; y < 16; y++) { + for (z = 0; z < 16; z++) { + for (x = 0; x < 16; x++, index++) { + filter.applyBlock(this); + } + } + } + } + + @Override + public void setBiome(BiomeType biome) { + set.setBiome(x, y, z, biome); + } + + @Override + public void setOrdinal(final int ordinal) { + delegate.set(this, (char) ordinal); + } + + @Override + public void setBlock(final BlockState state) { + delegate.set(this, state.getOrdinalChar()); + } + + @Override + public void setFullBlock(final BaseBlock block) { + delegate.set(this, block.getOrdinalChar()); + final CompoundTag nbt = block.getNbtData(); + if (nbt != null) { // TODO optimize check via ImmutableBaseBlock + set.setTile(x, yy + y, z, nbt); + } + } + + @Override + public final int getX() { + return xx + x; + } + + @Override + public final int getY() { + return yy + y; + } + + @Override + public final int getZ() { + return zz + z; + } + + @Override + public final int getLocalX() { + return x; + } + + @Override + public final int getLocalY() { + return y; + } + + @Override + public final int getLocalZ() { + return z; + } + + @Override + public final int getChunkX() { + return X; + } + + @Override + public final int getChunkZ() { + return Z; + } + + public final char getOrdinalChar() { + return getArr[index]; + } + + @Override + public final int getOrdinal() { + return getArr[index]; + } + + @Override + public final BlockState getBlock() { + final int ordinal = getArr[index]; + return BlockTypes.states[ordinal]; + } + + @Override + public final BaseBlock getFullBlock() { + final BlockState state = getBlock(); + final BlockMaterial material = state.getMaterial(); + if (material.hasContainer()) { + final CompoundTag tag = get.getTag(x, y + yy, z); + return state.toBaseBlock(tag); + } + return state.toBaseBlock(); + } + + @Override + public final CompoundTag getNbtData() { + return get.getTag(x, y + (layer << 4), z); + } + + @Override + public void setNbtData(CompoundTag tag) { + if (tag != null) { + set.setTile(x, y + yy, z, tag); + } + } + + @Override + public boolean hasNbtData() { + final BlockState state = getBlock(); + final BlockMaterial material = state.getMaterial(); + return material.hasContainer(); + } + /* + NORTH(Vector3.at(0, 0, -1), Flag.CARDINAL, 3, 1), + EAST(Vector3.at(1, 0, 0), Flag.CARDINAL, 0, 2), + SOUTH(Vector3.at(0, 0, 1), Flag.CARDINAL, 1, 3), + WEST(Vector3.at(-1, 0, 0), Flag.CARDINAL, 2, 0), + */ + + @Override + public final BlockState getBlockNorth() { + if (z > 0) { + return states[getArr[index - 16]]; + } + return getExtent().getBlock(getX(), getY(), getZ() - 1); + } + + @Override + public final BlockState getBlockEast() { + if (x < 15) { + return states[getArr[index + 1]]; + } + return getExtent().getBlock(getX() + 1, getY(), getZ()); + } + + @Override + public final BlockState getBlockSouth() { + if (z < 15) { + return states[getArr[index + 16]]; + } + return getExtent().getBlock(getX(), getY(), getZ() + 1); + } + + @Override + public final BlockState getBlockWest() { + if (x > 0) { + return states[getArr[index - 1]]; + } + return getExtent().getBlock(getX() - 1, getY(), getZ()); + } + + @Override + public final BlockState getBlockBelow() { + if (y > 0) { + return states[getArr[index - 256]]; + } + if (layer > 0) { + final int newLayer = layer - 1; + final CharGetBlocks chunk = this.get; + return states[chunk.sections[newLayer].get(chunk, newLayer, index + 3840)]; + } + return BlockTypes.__RESERVED__.getDefaultState(); + } + + @Override + public final BlockState getBlockAbove() { + if (y < 16) { + return states[getArr[index + 256]]; + } + if (layer < 16) { + final int newLayer = layer + 1; + final CharGetBlocks chunk = this.get; + return states[chunk.sections[newLayer].get(chunk, newLayer, index - 3840)]; + } + return BlockTypes.__RESERVED__.getDefaultState(); + } + + @Override + public final BlockState getBlockRelativeY(final int y) { + final int newY = this.y + y; + final int layerAdd = newY >> 4; + switch (layerAdd) { + case 0: + return states[getArr[this.index + (y << 8)]]; + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: { + final int newLayer = layer + layerAdd; + if (newLayer < 16) { + final int index = this.index + ((y & 15) << 8); + return states[get.sections[newLayer].get(get, newLayer, index)]; + } + break; + } + case -1: + case -2: + case -3: + case -4: + case -5: + case -6: + case -7: + case -8: + case -9: + case -10: + case -11: + case -12: + case -13: + case -14: + case -15: { + final int newLayer = layer + layerAdd; + if (newLayer >= 0) { + final int index = this.index + ((y & 15) << 8); + return states[get.sections[newLayer].get(get, newLayer, index)]; + } + break; + } + } + return BlockTypes.__RESERVED__.getDefaultState(); + } + + /* + Extent + */ + @Override + public char getOrdinalChar(Extent orDefault) { + return getOrdinalChar(); + } + + /* + Set delegate + */ + private SetDelegate initSet() { + setArr = set.getArray(layer); + return delegate = FULL; + } + + @Override + public BiomeType getBiomeType(int x, int z) { + if ((x >> 4) == X && (z >> 4) == Z) { + return get.getBiomeType(x & 15, z & 15); + } + return getExtent().getBiomeType(x, z); + } + + @Override + public boolean setBiome(int x, int y, int z, BiomeType biome) { + if ((x >> 4) == X && (z >> 4) == Z) { + return set.setBiome(x & 15, y, z & 15, biome); + } + return getExtent().setBiome(x, y, z, biome); + } + + private interface SetDelegate { + void set(CharFilterBlock block, char value); + } + + private static final SetDelegate NULL = new SetDelegate() { + @Override + public void set(final CharFilterBlock block, final char value) { + block.initSet().set(block, value); + } + }; + + private static final SetDelegate FULL = new SetDelegate() { + @Override + public final void set(final CharFilterBlock block, final char value) { + block.setArr[block.index] = value; + } + }; +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFilterBlock.java new file mode 100644 index 000000000..bc1957f51 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFilterBlock.java @@ -0,0 +1,30 @@ +package com.boydti.fawe.beta; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; + +import javax.annotation.Nullable; + +public abstract class ChunkFilterBlock extends SimpleFilterBlock { + public ChunkFilterBlock(Extent extent) { + super(extent); + } + + public abstract ChunkFilterBlock init(int X, int Z, IChunkGet chunk); + + public abstract ChunkFilterBlock init(final IChunkGet iget, final IChunkSet iset, final int layer); + + public abstract void flood(final IChunkGet iget, final IChunkSet iset, final int layer, Flood flood, FilterBlockMask mask); + + + public abstract void filter(Filter filter, int x, int y, int z); + + public abstract void filter(Filter filter, int minX, int minY, int minZ, int maxX, int maxY, int maxZ); + + public abstract void filter(Filter filter); + + public abstract void filter(Filter filter, int yStart, int yEnd); + + public abstract void filter(final Filter filter, final Region region); +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFuture.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFuture.java new file mode 100644 index 000000000..264eb4509 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFuture.java @@ -0,0 +1,60 @@ +package com.boydti.fawe.beta; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class ChunkFuture implements Future { + private final IChunk chunk; + private volatile boolean cancelled; + private volatile boolean done; + + public ChunkFuture(final IChunk chunk) { + this.chunk = chunk; + } + + public IChunk getChunk() { + return chunk; + } + + @Override + public boolean cancel(final boolean mayInterruptIfRunning) { + cancelled = true; + if (done) return false; + return true; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public boolean isDone() { + return done; + } + + @Override + public Void get() throws InterruptedException, ExecutionException { + synchronized (chunk) { + if (!done) { + this.wait(); + } + } + return null; + } + + @Override + public Void get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + synchronized (chunk) { + if (!done) { + this.wait(unit.toMillis(timeout)); + if (!done) { + throw new TimeoutException(); + } + } + } + return null; + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilter.java new file mode 100644 index 000000000..bbbe85f61 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilter.java @@ -0,0 +1,18 @@ +package com.boydti.fawe.beta; + +public class DelegateFilter implements IDelegateFilter { + private final Filter parent; + + public DelegateFilter(T parent) { + this.parent = parent; + } + @Override + public T getParent() { + return (T) parent; + } + + @Override + public Filter newInstance(Filter other) { + return new DelegateFilter(other); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilterBlock.java new file mode 100644 index 000000000..1dab05925 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilterBlock.java @@ -0,0 +1,697 @@ +package com.boydti.fawe.beta; + +import com.boydti.fawe.jnbt.anvil.generator.GenBase; +import com.boydti.fawe.jnbt.anvil.generator.Resource; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.MutableBlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.util.Countable; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; + +import javax.annotation.Nullable; +import java.util.Comparator; +import java.util.List; + +public class DelegateFilterBlock extends FilterBlock { + private final FilterBlock parent; + + public DelegateFilterBlock(FilterBlock parent) { + this.parent = parent; + } + + @Override + public Extent getExtent() { + return parent.getExtent(); + } + + @Override + public void setOrdinal(int ordinal) { + parent.setOrdinal(ordinal); + } + + @Override + public void setBlock(BlockState state) { + parent.setBlock(state); + } + + @Override + public void setFullBlock(BaseBlock block) { + parent.setFullBlock(block); + } + + @Override + public void setNbtData(@Nullable CompoundTag nbtData) { + parent.setNbtData(nbtData); + } + + @Override + public boolean hasNbtData() { + return parent.hasNbtData(); + } + + @Override + public void setBiome(BiomeType biome) { + parent.setBiome(biome); + } + + @Override + public int getOrdinal() { + return parent.getOrdinal(); + } + + @Override + public BlockState getBlock() { + return parent.getBlock(); + } + + @Override + public BaseBlock getFullBlock() { + return parent.getFullBlock(); + } + + @Override + public CompoundTag getNbtData() { + return parent.getNbtData(); + } + + @Override + public BlockVector3 getMinimumPoint() { + return parent.getMinimumPoint(); + } + + @Override + public BlockVector3 getMaximumPoint() { + return parent.getMaximumPoint(); + } + + @Override + public BlockState getBlock(int x, int y, int z) { + return parent.getBlock(x, y, z); + } + + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + return parent.getFullBlock(x, y, z); + } + + @Override + public BlockState getBlockBelow() { + return parent.getBlockBelow(); + } + + @Override + public BlockState getBlockAbove() { + return parent.getBlockAbove(); + } + + @Override + public BlockState getBlockNorth() { + return parent.getBlockNorth(); + } + + @Override + public BlockState getBlockEast() { + return parent.getBlockEast(); + } + + @Override + public BlockState getBlockSouth() { + return parent.getBlockSouth(); + } + + @Override + public BlockState getBlockWest() { + return parent.getBlockWest(); + } + + @Override + public BlockState getBlockRelativeY(int y) { + return parent.getBlockRelativeY(y); + } + + @Override + public int getX() { + return parent.getX(); + } + + @Override + public int getY() { + return parent.getY(); + } + + @Override + public int getZ() { + return parent.getZ(); + } + + @Override + public int getLocalX() { + return parent.getLocalX(); + } + + @Override + public int getLocalY() { + return parent.getLocalY(); + } + + @Override + public int getLocalZ() { + return parent.getLocalZ(); + } + + @Override + public int getChunkX() { + return parent.getChunkX(); + } + + @Override + public int getChunkZ() { + return parent.getChunkZ(); + } + + @Override + public boolean setOrdinal(Extent orDefault, int ordinal) { + return parent.setOrdinal(orDefault, ordinal); + } + + @Override + public boolean setBlock(Extent orDefault, BlockState state) { + return parent.setBlock(orDefault, state); + } + + @Override + public boolean setFullBlock(Extent orDefault, BaseBlock block) { + return parent.setFullBlock(orDefault, block); + } + + @Override + public boolean setBiome(Extent orDefault, BiomeType biome) { + return parent.setBiome(orDefault, biome); + } + + @Override + public int getOrdinal(Extent orDefault) { + return parent.getOrdinal(orDefault); + } + + @Override + public BlockState getBlock(Extent orDefault) { + return parent.getBlock(orDefault); + } + + @Override + public BaseBlock getFullBlock(Extent orDefault) { + return parent.getFullBlock(orDefault); + } + + @Override + public CompoundTag getNbtData(Extent orDefault) { + return parent.getNbtData(orDefault); + } + + @Override + public BlockState getOrdinalBelow(Extent orDefault) { + return parent.getOrdinalBelow(orDefault); + } + + @Override + public BlockState getStateAbove(Extent orDefault) { + return parent.getStateAbove(orDefault); + } + + @Override + public BlockState getStateRelativeY(Extent orDefault, int y) { + return parent.getStateRelativeY(orDefault, y); + } + + public static BlockVector3 at(double x, double y, double z) { + return BlockVector3.at(x, y, z); + } + + public static BlockVector3 at(int x, int y, int z) { + return BlockVector3.at(x, y, z); + } + + public static Comparator sortByCoordsYzx() { + return BlockVector3.sortByCoordsYzx(); + } + + @Override + public MutableBlockVector3 setComponents(double x, double y, double z) { + return parent.setComponents(x, y, z); + } + + @Override + public MutableBlockVector3 setComponents(int x, int y, int z) { + return parent.setComponents(x, y, z); + } + + @Override + public MutableBlockVector3 mutX(double x) { + return parent.mutX(x); + } + + @Override + public MutableBlockVector3 mutY(double y) { + return parent.mutY(y); + } + + @Override + public MutableBlockVector3 mutZ(double z) { + return parent.mutZ(z); + } + + @Override + public MutableBlockVector3 mutX(int x) { + return parent.mutX(x); + } + + @Override + public MutableBlockVector3 mutY(int y) { + return parent.mutY(y); + } + + @Override + public MutableBlockVector3 mutZ(int z) { + return parent.mutZ(z); + } + + @Override + public BlockVector3 toImmutable() { + return parent.toImmutable(); + } + +// @Override +// public BlockVector3 north() { +// return parent.north(); +// } +// +// @Override +// public BlockVector3 east() { +// return parent.east(); +// } +// +// @Override +// public BlockVector3 south() { +// return parent.south(); +// } +// +// @Override +// public BlockVector3 west() { +// return parent.west(); +// } + + @Override + public int getBlockX() { + return parent.getBlockX(); + } + + @Override + public BlockVector3 withX(int x) { + return parent.withX(x); + } + + @Override + public int getBlockY() { + return parent.getBlockY(); + } + + @Override + public BlockVector3 withY(int y) { + return parent.withY(y); + } + + @Override + public int getBlockZ() { + return parent.getBlockZ(); + } + + @Override + public BlockVector3 withZ(int z) { + return parent.withZ(z); + } + + @Override + public BlockVector3 add(BlockVector3 other) { + return parent.add(other); + } + + @Override + public BlockVector3 add(int x, int y, int z) { + return parent.add(x, y, z); + } + + @Override + public BlockVector3 add(BlockVector3... others) { + return parent.add(others); + } + + @Override + public BlockVector3 subtract(BlockVector3 other) { + return parent.subtract(other); + } + + @Override + public BlockVector3 subtract(int x, int y, int z) { + return parent.subtract(x, y, z); + } + + @Override + public BlockVector3 subtract(BlockVector3... others) { + return parent.subtract(others); + } + + @Override + public BlockVector3 multiply(BlockVector3 other) { + return parent.multiply(other); + } + + @Override + public BlockVector3 multiply(int x, int y, int z) { + return parent.multiply(x, y, z); + } + + @Override + public BlockVector3 multiply(BlockVector3... others) { + return parent.multiply(others); + } + + @Override + public BlockVector3 multiply(int n) { + return parent.multiply(n); + } + + @Override + public BlockVector3 divide(BlockVector3 other) { + return parent.divide(other); + } + + @Override + public BlockVector3 divide(int x, int y, int z) { + return parent.divide(x, y, z); + } + + @Override + public BlockVector3 divide(int n) { + return parent.divide(n); + } + + @Override + public double length() { + return parent.length(); + } + + @Override + public int lengthSq() { + return parent.lengthSq(); + } + + @Override + public double distance(BlockVector3 other) { + return parent.distance(other); + } + + @Override + public int distanceSq(BlockVector3 other) { + return parent.distanceSq(other); + } + + @Override + public BlockVector3 normalize() { + return parent.normalize(); + } + + @Override + public double dot(BlockVector3 other) { + return parent.dot(other); + } + + @Override + public BlockVector3 cross(BlockVector3 other) { + return parent.cross(other); + } + + @Override + public boolean containedWithin(BlockVector3 min, BlockVector3 max) { + return parent.containedWithin(min, max); + } + + @Override + public BlockVector3 clampY(int min, int max) { + return parent.clampY(min, max); + } + + @Override + public BlockVector3 floor() { + return parent.floor(); + } + + @Override + public BlockVector3 ceil() { + return parent.ceil(); + } + + @Override + public BlockVector3 round() { + return parent.round(); + } + + @Override + public BlockVector3 abs() { + return parent.abs(); + } + + @Override + public BlockVector3 transform2D(double angle, double aboutX, double aboutZ, double translateX, double translateZ) { + return parent.transform2D(angle, aboutX, aboutZ, translateX, translateZ); + } + + @Override + public double toPitch() { + return parent.toPitch(); + } + + @Override + public double toYaw() { + return parent.toYaw(); + } + + @Override + public BlockVector3 getMinimum(BlockVector3 v2) { + return parent.getMinimum(v2); + } + + @Override + public BlockVector3 getMaximum(BlockVector3 v2) { + return parent.getMaximum(v2); + } + + @Override + public char getOrdinalChar(Extent orDefault) { + return parent.getOrdinalChar(orDefault); + } + + @Override + public BlockVector2 toBlockVector2() { + return parent.toBlockVector2(); + } + + @Override + public Vector3 toVector3() { + return parent.toVector3(); + } + + @Override + public int hashCode() { + return parent.hashCode(); + } + + @Override + public String toString() { + return parent.toString(); + } + + @Override + public List getEntities(Region region) { + return parent.getEntities(region); + } + + @Override + public List getEntities() { + return parent.getEntities(); + } + + @Override + @Nullable + public Entity createEntity(Location location, BaseEntity entity) { + return parent.createEntity(location, entity); + } + + @Override + public int getHighestTerrainBlock(int x, int z, int minY, int maxY) { + return parent.getHighestTerrainBlock(x, z, minY, maxY); + } + + @Override + public int getHighestTerrainBlock(int x, int z, int minY, int maxY, Mask filter) { + return parent.getHighestTerrainBlock(x, z, minY, maxY, filter); + } + + @Override + public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) { + return parent.getNearestSurfaceLayer(x, z, y, minY, maxY); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, boolean ignoreAir) { + return parent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) { + return parent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) { + return parent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) { + return parent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, boolean ignoreAir) { + return parent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir); + } + + @Override + public void addCaves(Region region) throws WorldEditException { + parent.addCaves(region); + } + + @Override + public void generate(Region region, GenBase gen) throws WorldEditException { + parent.generate(region, gen); + } + + @Override + public void addSchems(Region region, Mask mask, List clipboards, int rarity, boolean rotate) throws WorldEditException { + parent.addSchems(region, mask, clipboards, rarity, rotate); + } + + @Override + public void spawnResource(Region region, Resource gen, int rarity, int frequency) throws WorldEditException { + parent.spawnResource(region, gen, rarity, frequency); + } + + @Override + public boolean contains(BlockVector3 pt) { + return parent.contains(pt); + } + + @Override + public void addOre(Region region, Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException { + parent.addOre(region, mask, material, size, frequency, rarity, minY, maxY); + } + + @Override + public void addOres(Region region, Mask mask) throws WorldEditException { + parent.addOres(region, mask); + } + + @Override + public List> getBlockDistribution(Region region) { + return parent.getBlockDistribution(region); + } + + @Override + public List> getBlockDistributionWithData(Region region) { + return parent.getBlockDistributionWithData(region); + } + + @Override + public BlockArrayClipboard lazyCopy(Region region) { + return parent.lazyCopy(region); + } + + @Override + @Nullable + public Operation commit() { + return parent.commit(); + } + + @Override + public int getMaxY() { + return parent.getMaxY(); + } + + @Override + public BlockState getBlock(BlockVector3 position) { + return parent.getBlock(position); + } + + @Override + public BlockType getBlockType(BlockVector3 position) { + return parent.getBlockType(position); + } + + @Override + public BaseBlock getFullBlock(BlockVector3 position) { + return parent.getFullBlock(position); + } + + @Override + public BiomeType getBiome(BlockVector2 position) { + return parent.getBiome(position); + } + + @Override + public BiomeType getBiomeType(int x, int z) { + return parent.getBiomeType(x, z); + } + + @Override + public > boolean setBlock(BlockVector3 position, T block) throws WorldEditException { + return parent.setBlock(position, block); + } + + @Override + public > boolean setBlock(int x, int y, int z, T block) throws WorldEditException { + return parent.setBlock(x, y, z, block); + } + + @Override + public boolean setBiome(BlockVector2 position, BiomeType biome) { + return parent.setBiome(position, biome); + } + + @Override + public boolean setBiome(int x, int y, int z, BiomeType biome) { + return parent.setBiome(x, y, z, biome); + } + + @Override + public String getNbtId() { + return parent.getNbtId(); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/DirectionMask.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/DirectionMask.java new file mode 100644 index 000000000..4efce15ec --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/DirectionMask.java @@ -0,0 +1,5 @@ +package com.boydti.fawe.beta; + +public interface DirectionMask { + boolean apply(int fromX, int fromY, int fromZ, int toX, int toY, int toZ); +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java new file mode 100644 index 000000000..2f19852c3 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/Filter.java @@ -0,0 +1,70 @@ +package com.boydti.fawe.beta; + +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.block.BaseBlock; + +import javax.annotation.Nullable; + +/** + * A filter is an interface used for setting blocks + */ +public interface Filter { + /** + * Check whether a chunk should be read + * + * @param cx + * @param cz + * @return + */ + default boolean appliesChunk(final int cx, final int cz) { + return true; + } + + /** + * Do something with the IChunk
+ * - Return null if you don't want to filter blocks
+ * - Return the chunk if you do want to filter blocks
+ * + * @param chunk + * @return + */ + default IChunk applyChunk(final IChunk chunk, @Nullable Region region) { + return chunk; + } + + default boolean appliesLayer(IChunk chunk, int layer) { + return true; + } + + /** + * Make changes to the block here
+ * - e.g. block.setId(...)
+ * - Note: Performance is critical here
+ * + * @param block + */ + default void applyBlock(final FilterBlock block) { + } + + /** + * Do something with the IChunk after block filtering
+ * + * @param chunk + * @return + */ + default void finishChunk(final IChunk chunk) { + } + + /** + * Fork this for use by another thread + * - Typically filters are simple and don't need to create another copy to be thread safe here + * @return this + */ + default Filter fork() { + return this; + } + + default void join() { + + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java new file mode 100644 index 000000000..ed2a84be4 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java @@ -0,0 +1,169 @@ +package com.boydti.fawe.beta; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.blocks.TileEntityBlock; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; + +import javax.annotation.Nullable; + +import static com.sk89q.worldedit.world.block.BlockTypes.states; + +public abstract class FilterBlock extends BlockVector3 implements Extent, TileEntityBlock { + public abstract Extent getExtent(); + + public abstract void setOrdinal(int ordinal); + + public abstract void setBlock(BlockState state); + + public abstract void setFullBlock(BaseBlock block); + + public void setBiome(BiomeType biome) { + setBiome(getX(), getY(), getZ(), biome); + } + + public abstract int getOrdinal(); + + public abstract BlockState getBlock(); + + public abstract BaseBlock getFullBlock(); + + public abstract CompoundTag getNbtData(); + + public abstract void setNbtData(@Nullable CompoundTag nbtData); + + public boolean hasNbtData() { + return getNbtData() != null; + } + + @Override + public BlockVector3 getMinimumPoint() { + return getExtent().getMinimumPoint(); + } + + @Override + public BlockVector3 getMaximumPoint() { + return getExtent().getMaximumPoint(); + } + + @Override + public BlockState getBlock(int x, int y, int z) { + return getExtent().getBlock(x, y, z); + } + + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + return getExtent().getFullBlock(x, y, z); + } + + public BlockState getBlockBelow() { + return getBlock(getX(), getY() - 1, getZ()); + } + + public BlockState getBlockAbove() { + return getBlock(getX(), getY() + 1, getZ()); + } + + public BlockState getBlockNorth() { + return getBlock(getX(), getY(), getZ() - 1); + } + + public BlockState getBlockEast() { + return getBlock(getX() + 1, getY(), getZ()); + } + + public BlockState getBlockSouth() { + return getBlock(getX(), getY(), getZ() + 1); + } + + public BlockState getBlockWest() { + return getBlock(getX() - 1, getY(), getZ()); + } + + public BlockState getBlockRelativeY(final int y) { + return getBlock(getX(), getY() + y , getZ()); + } + + @Override + public abstract int getX(); + + @Override + public abstract int getY(); + + @Override + public abstract int getZ(); + + public int getLocalX() { + return getX() & 15; + } + + public int getLocalY() { + return getY() & 15; + } + + public int getLocalZ() { + return getZ() & 15; + } + + public int getChunkX() { + return getX() >> 4; + } + + public int getChunkZ() { + return getZ() >> 4; + } + + /* + Extent + */ + public boolean setOrdinal(Extent orDefault, int ordinal) { + setOrdinal(ordinal); + return true; + } + + public boolean setBlock(Extent orDefault, BlockState state) { + setBlock(state); + return true; + } + + public boolean setFullBlock(Extent orDefault, BaseBlock block) { + setFullBlock(block); + return true; + } + + public boolean setBiome(Extent orDefault, BiomeType biome) { + setBiome(biome); + return true; + } + + public int getOrdinal(Extent orDefault) { + return getOrdinal(); + } + + public BlockState getBlock(Extent orDefault) { + return getBlock(); + } + + public BaseBlock getFullBlock(Extent orDefault) { + return getFullBlock(); + } + + public CompoundTag getNbtData(Extent orDefault) { + return getNbtData(); + } + + public BlockState getOrdinalBelow(Extent orDefault) { + return getBlockBelow(); + } + + public BlockState getStateAbove(Extent orDefault) { + return getBlockAbove(); + } + + public BlockState getStateRelativeY(Extent orDefault, final int y) { + return getBlockRelativeY(y); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlockMask.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlockMask.java new file mode 100644 index 000000000..e7728435c --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlockMask.java @@ -0,0 +1,5 @@ +package com.boydti.fawe.beta; + +public interface FilterBlockMask { + boolean applyBlock(final FilterBlock block); +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/Flood.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/Flood.java new file mode 100644 index 000000000..bfc567181 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/Flood.java @@ -0,0 +1,192 @@ +package com.boydti.fawe.beta; + +import com.boydti.fawe.Fawe; +import com.boydti.fawe.beta.implementation.QueueHandler; +import com.boydti.fawe.beta.implementation.WorldChunkCache; +import com.boydti.fawe.util.MathMan; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.world.World; +import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; + +import java.util.concurrent.ConcurrentLinkedQueue; + +public class Flood { + private final int maxBranch; + private final int maxDepth; + private final Direction[] directions; + + private int[] queue; + private long[] visit; + + private int[][] queues; + private long[][] visits; + + private int X, Y, Z; + + private ConcurrentLinkedQueue queuePool = new ConcurrentLinkedQueue<>(); + private final Long2ObjectLinkedOpenHashMap chunkVisits; + private final Long2ObjectLinkedOpenHashMap chunkQueues; + + public Flood(int maxBranch, int maxDepth, Direction[] directions) { + this.maxBranch = maxBranch; + this.maxDepth = maxDepth; + this.directions = directions; + + this.queues = new int[27][]; + this.visits = new long[27][]; + + this.chunkVisits = new Long2ObjectLinkedOpenHashMap<>(); + this.chunkQueues = new Long2ObjectLinkedOpenHashMap<>(); + } + + public synchronized void run(World world) { + QueueHandler queueHandler = Fawe.get().getQueueHandler(); + IQueueExtent fq = queueHandler.getQueue(world); + while (!chunkQueues.isEmpty()) { + long firstKey = chunkQueues.firstLongKey(); + int X = MathMan.unpairIntX(firstKey); + int Z = MathMan.unpairIntY(firstKey); + int[][] chunkQueue = chunkQueues.get(firstKey); + // apply + } + } + + private void init(int X, int Y, int Z) { + this.X = X; + this.Y = Y; + this.Z = Z; + } + + public void start(int x, int y, int z) { + push(x, y, z, 0); + } + + private void push(int x, int y, int z, int depth) { + int X = x >> 4; + int Z = z >> 4; + long pair = MathMan.pairInt(X, Z); + int layer = y >> 4; + int[] section = getOrCreateQueue(pair, layer); + int val = (x & 15) + ((z & 15) << 4) + ((y & 15) << 8) + (depth << 12); + push(section, val); + } + + private int[] getOrCreateQueue(long pair, int layer) { + int[][] arrs = chunkQueues.get(pair); + if (arrs == null) { + chunkQueues.put(pair, arrs = new int[16][]); + } + int[] section = arrs[layer]; + if (section == null) { + arrs[layer] = section = newQueue(); + } + return section; + } + + private int[] newQueue() { + int[] arr = queuePool.poll(); + if (arr != null) { + arr[0] = 2; + arr[1] = 2; + return arr; + } + return new int[4096]; + } + + public int poll() { + int index = queue[0]; + if (index == queue[1]) { + return -1; + } + queue[0] = index + 1; + return queue[index]; + } + + private void push(int[] queue, int val) { + int indexStart = queue[0]; + int indexEnd = queue[1]; + push(indexStart, indexEnd, queue, val); + } + + private void push(int indexStart, int indexEnd, int[] queue, int val) { + if (indexStart > 2) { + queue[0] = --indexStart; + queue[indexStart] = val; + } else { + queue[indexEnd] = val; + queue[0] = ++indexEnd; + } + } + + public Direction[] getDirections() { + return directions; + } + + public int getMaxBranch() { + return maxBranch; + } + + public int getMaxDepth() { + return maxDepth; + } + + public void apply(int x, int y, int z, int depth) { + for (int i = 0, j = 0; i < directions.length && j < maxBranch; i++) { + final Direction dir = directions[i]; + final int ty = y + dir.getBlockY(); + final int tx = x + dir.getBlockX(); + final int tz = z + dir.getBlockZ(); + + int index; + long[] visit; + int[] queue; + final int or = tx | ty | tz; + if (or > 15 || or < 0) { + visit = this.visit; + queue = this.queue; + index = tx + (tz << 4) + (ty << 8); + } else { + int nextX = tx >> 4; + int nextY = ty >> 4; + int nextZ = tz >> 4; + int sectionIndex = nextX + nextZ * 3 + nextZ * 9 + 13; + visit = visits[sectionIndex]; + queue = queues[sectionIndex]; + if (visit == null || queue == null) { + long pair = MathMan.pairInt(X + nextX, Z + nextZ); + int layer = Y + nextY; + if (layer < 0 || layer > 15) { + continue; + } + queues[sectionIndex] = queue = getOrCreateQueue(pair, layer); + } + index = (tx & 15) + ((tz & 15) << 4) + ((ty & 15) << 8); + } + if (!getAndSet(visit, index)) { + j++; + push(queue, index + (depth << 12)); + } + } + } + + public void set(long[] bits, int i) { + bits[i >> 6] |= (1L << (i & 0x3F)); + } + + public final boolean getAndSet(long[] bits, int i) { + int index = i >> 6; + long offset = (1L << (i & 0x3F)); + long val = bits[index]; + if ((val & offset) != 0) { + return true; + } else { + bits[index] |= offset; + return false; + } + } + + public boolean get(long[] bits, final int i) { + return (bits[i >> 6] & (1L << (i & 0x3F))) != 0; + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IBlocks.java new file mode 100644 index 000000000..fce4a574d --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IBlocks.java @@ -0,0 +1,10 @@ +package com.boydti.fawe.beta; + +/** + * Shared interface for IGetBlocks and ISetBlocks + */ +public interface IBlocks extends Trimable { + boolean hasSection(int layer); + + IChunkSet reset(); +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java new file mode 100644 index 000000000..26be59e53 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java @@ -0,0 +1,89 @@ +package com.boydti.fawe.beta; + +import com.sk89q.worldedit.math.MutableBlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import javax.annotation.Nullable; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +/** + * Represents a chunk in the queue {@link IQueueExtent} + * Used for getting and setting blocks / biomes / entities + */ +public interface IChunk> extends Trimable, Callable { + /** + * Initialize at the location + * @param extent + * @param X + * @param Z + */ + void init(IQueueExtent extent, int X, int Z); + + int getX(); + + int getZ(); + + /** + * If the chunk is a delegate, returns it's paren'ts root + * @return root IChunk + */ + default IChunk getRoot() { + return this; + } + + /** + * @return true if no changes are queued for this chunk + */ + boolean isEmpty(); + + /** + * Apply the queued changes to the world
+ * The future returned may return another future
+ * To ensure completion keep calling {@link Future#get()} on each result + * @return Futures + */ + T call(); + + /** + * Call and join + * @throws ExecutionException + * @throws InterruptedException + */ + default void join() throws ExecutionException, InterruptedException { + T future = call(); + while (future != null) { + future = future.get(); + } + return; + } + + /** + * Filter + * @param filter the filter + * @param block The filter block + * @param region The region allowed to filter (may be null) + * @param unitialized a mutable block vector (buffer) + * @param unitialized2 a mutable block vector (buffer) + */ + void filterBlocks(Filter filter, ChunkFilterBlock block, @Nullable Region region); + + void flood(Flood flood, FilterBlockMask mask, ChunkFilterBlock block); + + /* set - queues a change */ + boolean setBiome(int x, int y, int z, BiomeType biome); + + boolean setBlock(int x, int y, int z, BlockStateHolder block); + + /* get - from the world */ + BiomeType getBiome(int x, int z); + + BlockState getBlock(int x, int y, int z); + + BaseBlock getFullBlock(int x, int y, int z); +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkGet.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkGet.java new file mode 100644 index 000000000..a76894912 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkGet.java @@ -0,0 +1,30 @@ +package com.boydti.fawe.beta; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.extent.InputExtent; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; + +/** + * Interface for getting blocks + */ +public interface IChunkGet extends IBlocks, Trimable, InputExtent { + @Override + BaseBlock getFullBlock(int x, int y, int z); + + @Override + BiomeType getBiomeType(int x, int z); + + @Override + BlockState getBlock(int x, int y, int z); + + CompoundTag getTag(int x, int y, int z); + + @Override + boolean trim(boolean aggressive); + + default void optimize() { + + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkSet.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkSet.java new file mode 100644 index 000000000..35efd352a --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkSet.java @@ -0,0 +1,51 @@ +package com.boydti.fawe.beta; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.extent.OutputExtent; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import javax.annotation.Nullable; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +/** + * Interface for setting blocks + */ +public interface IChunkSet extends IBlocks, OutputExtent { + boolean setBiome(int x, int y, int z, BiomeType biome); + + boolean setBlock(int x, int y, int z, BlockStateHolder holder); + + boolean isEmpty(); + + void setTile(int x, int y, int z, CompoundTag tile); + + void setEntity(CompoundTag tag); + + void removeEntity(UUID uuid); + + BlockState getBlock(int x, int y, int z); + + char[] getArray(int layer); + + BiomeType[] getBiomes(); + + Map getTiles(); + + Set getEntities(); + + Set getEntityRemoves(); + + @Override + IChunkSet reset(); + + @Nullable + @Override + default Operation commit() { + return null; + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java new file mode 100644 index 000000000..e36529fc8 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java @@ -0,0 +1,109 @@ +package com.boydti.fawe.beta; + +import com.sk89q.worldedit.math.MutableBlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import javax.annotation.Nullable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +/** + * Delegate for IChunk + * @param parent class + */ +public interface IDelegateChunk extends IChunk { + U getParent(); + + default IChunk getRoot() { + IChunk root = getParent(); + while (root instanceof IDelegateChunk) { + root = ((IDelegateChunk) root).getParent(); + } + return root; + } + + @Override + default void flood(Flood flood, FilterBlockMask mask, ChunkFilterBlock block) { + getParent().flood(flood, mask, block); + } + + @Override + default boolean setBiome(final int x, final int y, final int z, final BiomeType biome) { + return getParent().setBiome(x, y, z, biome); + } + + @Override + default boolean setBlock(final int x, final int y, final int z, final BlockStateHolder holder) { + return getParent().setBlock(x, y, z, holder); + } + + @Override + default BiomeType getBiome(final int x, final int z) { + return getParent().getBiome(x, z); + } + + @Override + default BlockState getBlock(final int x, final int y, final int z) { + return getParent().getBlock(x, y, z); + } + + @Override + default BaseBlock getFullBlock(final int x, final int y, final int z) { + return getParent().getFullBlock(x, y, z); + } + + @Override + default void init(final IQueueExtent extent, final int X, final int Z) { + getParent().init(extent, X, Z); + } + + @Override + default int getX() { + return getParent().getX(); + } + + @Override + default int getZ() { + return getParent().getZ(); + } + + + @Override + default boolean trim(final boolean aggressive) { + return getParent().trim(aggressive); + } + + @Override + default Future call() { + return getParent().call(); + } + + @Override + default void join() throws ExecutionException, InterruptedException { + getParent().join(); + } + + @Override + default void filterBlocks(Filter filter, ChunkFilterBlock block, @Nullable Region region) { + getParent().filterBlocks(filter, block, region); + } + + @Override + default boolean isEmpty() { + return getParent().isEmpty(); + } + + default T findParent(final Class clazz) { + IChunk root = getParent(); + if (clazz.isAssignableFrom(root.getClass())) return (T) root; + while (root instanceof IDelegateChunk) { + root = ((IDelegateChunk) root).getParent(); + if (clazz.isAssignableFrom(root.getClass())) return (T) root; + } + return null; + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateFilter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateFilter.java new file mode 100644 index 000000000..e39b1b703 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateFilter.java @@ -0,0 +1,52 @@ +package com.boydti.fawe.beta; + +import com.sk89q.worldedit.regions.Region; + +import javax.annotation.Nullable; + +public interface IDelegateFilter extends Filter { + Filter getParent(); + + @Override + default boolean appliesChunk(int cx, int cz) { + return getParent().appliesChunk(cx, cz); + } + + @Override + default IChunk applyChunk(IChunk chunk, @Nullable Region region) { + return getParent().applyChunk(chunk, region); + } + + @Override + default boolean appliesLayer(IChunk chunk, int layer) { + return getParent().appliesLayer(chunk, layer); + } + + @Override + default void applyBlock(FilterBlock block) { + getParent().applyBlock(block); + } + + @Override + default void finishChunk(IChunk chunk) { + getParent().finishChunk(chunk); + } + + @Override + default void join() { + getParent().join(); + } + + @Override + default Filter fork() { + Filter fork = getParent().fork(); + if (fork != getParent()) { + return newInstance(fork); + } + return this; + } + + default Filter newInstance(Filter other) { + throw new UnsupportedOperationException("Not implemented"); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateQueueExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateQueueExtent.java new file mode 100644 index 000000000..f05a1b2e5 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateQueueExtent.java @@ -0,0 +1,47 @@ +package com.boydti.fawe.beta; + +import com.boydti.fawe.beta.implementation.WorldChunkCache; + +import java.util.concurrent.Future; + +/** + * Delegate for IQueueExtent + */ +public interface IDelegateQueueExtent extends IQueueExtent { + IQueueExtent getParent(); + + @Override + default void init(final WorldChunkCache cache) { + getParent().init(cache); + } + + @Override + default IChunk getCachedChunk(final int X, final int Z) { + return getParent().getCachedChunk(X, Z); + } + + @Override + default Future submit(final IChunk chunk) { + return getParent().submit(chunk); + } + + @Override + default IChunk create(final boolean full) { + return getParent().create(full); + } + + @Override + default IChunk wrap(final IChunk root) { + return getParent().wrap(root); + } + + @Override + default void flush() { + getParent().flush(); + } + + @Override + default boolean trim(final boolean aggressive) { + return getParent().trim(aggressive); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java new file mode 100644 index 000000000..5e9bfffbe --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java @@ -0,0 +1,104 @@ +package com.boydti.fawe.beta; + +import com.boydti.fawe.beta.implementation.WorldChunkCache; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import java.io.Flushable; +import java.util.concurrent.Future; +import java.util.function.Supplier; + +/** + * TODO: implement Extent (need to refactor Extent first) + * Interface for a queue based extent which uses chunks + */ +public interface IQueueExtent extends Flushable, Trimable, Extent { + void init(WorldChunkCache world); + + /** + * Get the {@link WorldChunkCache} + * @return + */ + IChunkGet getCachedGet(int X, int Z, Supplier supplier); + + /** + * Get the IChunk at a position (and cache it if it's not already) + * @param X + * @param Z + * @return IChunk + */ + IChunk getCachedChunk(int X, int Z); + + /** + * Submit the chunk so that it's changes are applied to the world + * @param chunk + * @return result + */ + > T submit(IChunk chunk); + + default boolean setBlock(final int x, final int y, final int z, final BlockStateHolder state) { + final IChunk chunk = getCachedChunk(x >> 4, z >> 4); + return chunk.setBlock(x & 15, y, z & 15, state); + } + + default boolean setBiome(final int x, final int y, final int z, final BiomeType biome) { + final IChunk chunk = getCachedChunk(x >> 4, z >> 4); + return chunk.setBiome(x & 15, y, z & 15, biome); + } + + default BlockState getBlock(final int x, final int y, final int z) { + final IChunk chunk = getCachedChunk(x >> 4, z >> 4); + return chunk.getBlock(x & 15, y, z & 15); + } + + @Override + default BaseBlock getFullBlock(int x, int y, int z) { + final IChunk chunk = getCachedChunk(x >> 4, z >> 4); + return chunk.getFullBlock(x & 15, y, z & 15); + } + + default BiomeType getBiome(final int x, final int z) { + final IChunk chunk = getCachedChunk(x >> 4, z >> 4); + return chunk.getBiome(x & 15, z & 15); + } + + @Override + default BlockVector3 getMinimumPoint() { + return getWorld().getMinimumPoint(); + } + + @Override + default BlockVector3 getMaximumPoint() { + return getWorld().getMaximumPoint(); + } + /** + * Create a new root IChunk object
+ * - Full chunks will be reused, so a more optimized chunk can be returned in that case
+ * - Don't wrap the chunk, that should be done in {@link #wrap(IChunk)} + * @param full + * @return + */ + IChunk create(boolean full); + + /** + * Wrap the chunk object (i.e. for region restrictions / limits etc.) + * @param root + * @return wrapped chunk + */ + default IChunk wrap(final IChunk root) { + return root; + } + + /** + * Flush all changes to the world + * - Best to call this async so it doesn't hang the server + */ + @Override + void flush(); + + ChunkFilterBlock initFilterBlock(); +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/NorthVector.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/NorthVector.java new file mode 100644 index 000000000..94279a6aa --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/NorthVector.java @@ -0,0 +1,92 @@ +package com.boydti.fawe.beta; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; + +public class NorthVector extends BlockVector3 { + private final BlockVector3 parent; + + public NorthVector(BlockVector3 parent) { + this.parent = parent; + } + +// @Override +// public BlockVector3 south(BlockVector3 orDefault) { +// return parent; +// } + + @Override + public int getX() { + return parent.getX(); + } + + @Override + public int getY() { + return parent.getY(); + } + + @Override + public int getZ() { + return parent.getZ(); + } + + public boolean setOrdinal(Extent orDefault, int ordinal) { + return orDefault.setBlock(this, BlockState.getFromOrdinal(ordinal)); + } + + public boolean setBlock(Extent orDefault, BlockState state) { + return orDefault.setBlock(this, state); + } + + public boolean setFullBlock(Extent orDefault, BaseBlock block) { + return orDefault.setBlock(this, block); + } + + public boolean setBiome(Extent orDefault, BiomeType biome) { + return orDefault.setBiome(getX(), getY(), getZ(), biome); + } + + public int getOrdinal(Extent orDefault) { + return getBlock(orDefault).getOrdinal(); + } + + public char getOrdinalChar(Extent orDefault) { + return (char) getOrdinal(orDefault); + } + + public BlockState getBlock(Extent orDefault) { + return orDefault.getBlock(this); + } + + public BaseBlock getFullBlock(Extent orDefault) { + return orDefault.getFullBlock(this); + } + + public CompoundTag getNbtData(Extent orDefault) { + return orDefault.getFullBlock(getX(), getY(), getZ()).getNbtData(); + } + + public BlockState getOrdinalBelow(Extent orDefault) { + return getStateRelative(orDefault, 0, -1, 0); + } + + public BlockState getStateAbove(Extent orDefault) { + return getStateRelative(orDefault, 0, 1, 0); + } + + public BlockState getStateRelativeY(Extent orDefault, final int y) { + return getStateRelative(orDefault, 0, y, 0); + } + + public BlockState getStateRelative(Extent orDefault, final int x, final int y, final int z) { + return getFullBlockRelative(orDefault, x, y, z).toBlockState(); + } + + public BaseBlock getFullBlockRelative(Extent orDefault, int x, int y, int z) { + return orDefault.getFullBlock(x + getX(), y + getY(), z + getZ()); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/SimpleFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/SimpleFilterBlock.java new file mode 100644 index 000000000..b8d865aec --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/SimpleFilterBlock.java @@ -0,0 +1,16 @@ +package com.boydti.fawe.beta; + +import com.sk89q.worldedit.extent.Extent; + +public abstract class SimpleFilterBlock extends FilterBlock { + private final Extent extent; + + public SimpleFilterBlock(Extent extent) { + this.extent = extent; + } + + @Override + public final Extent getExtent() { + return extent; + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/SingleFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/SingleFilterBlock.java new file mode 100644 index 000000000..39a2c04a0 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/SingleFilterBlock.java @@ -0,0 +1,98 @@ +package com.boydti.fawe.beta; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; + +import javax.annotation.Nullable; + +public class SingleFilterBlock extends FilterBlock { + + private BaseBlock block; + private int x, y, z; + + public SingleFilterBlock init(int x, int y, int z, BaseBlock block) { + this.x = x; + this.y = y; + this.z = z; + this.block = block; + return this; + } + + @Override + public Extent getExtent() { + return this; + } + + @Override + public void setOrdinal(int ordinal) { + setBlock(BlockState.getFromOrdinal(ordinal)); + } + + @Override + public void setBlock(BlockState state) { + setFullBlock(state.toBaseBlock(block.getNbtData())); + } + + @Override + public void setFullBlock(BaseBlock block) { + this.block = block; + } + + @Override + public void setNbtData(@Nullable CompoundTag nbtData) { + block = block.toBaseBlock(nbtData); + } + + @Override + public int getOrdinal() { + return block.getOrdinal(); + } + +// @Override +// public BaseBlock getFullBlockRelative(int x, int y, int z) { +// return block; +// } + + @Override + public BlockState getBlock() { + return block.toBlockState(); + } + + @Override + public BaseBlock getFullBlock() { + return block; + } + + @Override + public CompoundTag getNbtData() { + return block.getNbtData(); + } + + @Override + public int getX() { + return x; + } + + @Override + public int getY() { + return y; + } + + @Override + public int getZ() { + return z; + } + + @Override + public BlockVector3 getMinimumPoint() { + return BlockVector3.at(x, y, z); + } + + @Override + public BlockVector3 getMaximumPoint() { + return BlockVector3.at(x, y, z); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/Trimable.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/Trimable.java new file mode 100644 index 000000000..34efe59ae --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/Trimable.java @@ -0,0 +1,14 @@ +package com.boydti.fawe.beta; + +/** + * Interface for objects that can be trimmed (memory related)
+ * - Trimming will reduce it's memory footprint + */ +public interface Trimable { + /** + * Trim the object, reducing it's memory footprint + * @param aggressive if trimming should be aggressive e.g. Not return early when the first element cannot be trimmed + * @return if this object is empty at the end of the trim, and can therefore be deleted + */ + boolean trim(boolean aggressive); +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/ArrayImageMask.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/ArrayImageMask.java new file mode 100644 index 000000000..41ceed910 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/ArrayImageMask.java @@ -0,0 +1,26 @@ +package com.boydti.fawe.beta.filters; + +import com.boydti.fawe.beta.DelegateFilter; +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.FilterBlock; +import com.boydti.fawe.beta.FilterBlockMask; + +import java.awt.image.BufferedImage; +import java.util.concurrent.ThreadLocalRandom; + +public class ArrayImageMask implements FilterBlockMask { + private final ThreadLocalRandom r; + private final boolean white; + private final BufferedImage img; + + public ArrayImageMask(BufferedImage img, boolean white) { + this.img = img; + this.white = white; + this.r = ThreadLocalRandom.current(); + } + @Override + public boolean applyBlock(FilterBlock block) { + int height = img.getRGB(block.getX(), block.getZ()) & 0xFF; + return ((height == 255 || height > 0 && !white && r.nextInt(256) <= height)); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/CountFilter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/CountFilter.java new file mode 100644 index 000000000..8dda75900 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/CountFilter.java @@ -0,0 +1,38 @@ +package com.boydti.fawe.beta.filters; + +import com.boydti.fawe.beta.FilterBlock; + +public class CountFilter extends ForkedFilter { + private int total; + + public CountFilter() { + super(null); + } + + private CountFilter(CountFilter root) { + super(root); + } + + @Override + public CountFilter init() { + return new CountFilter(this); + } + + @Override + public void join(CountFilter filter) { + this.total += filter.getTotal(); + } + + /* + Implementation + */ + + @Override + public final void applyBlock(final FilterBlock block) { + total++; + } + + public int getTotal() { + return total; + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/DistrFilter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/DistrFilter.java new file mode 100644 index 000000000..bde69e284 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/DistrFilter.java @@ -0,0 +1,107 @@ +package com.boydti.fawe.beta.filters; + +import com.boydti.fawe.beta.FilterBlock; +import com.boydti.fawe.config.BBC; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.function.mask.ABlockMask; +import com.sk89q.worldedit.util.Countable; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class DistrFilter extends ForkedFilter { + private final int[] counter = new int[BlockTypes.states.length]; + + public DistrFilter() { + super(null); + } + + private DistrFilter(DistrFilter root) { + super(root); + } + + @Override + public DistrFilter init() { + return new DistrFilter(this); + } + + @Override + public void join(DistrFilter filter) { + for (int i = 0; i < filter.counter.length; i++) { + this.counter[i] += filter.counter[i]; + } + } + + /* + Implementation + */ + + @Override + public final void applyBlock(final FilterBlock block) { + counter[block.getOrdinal()]++; + } + + public int getTotal(ABlockMask mask) { + int total = 0; + for (int i = 0; i < counter.length; i++) { + int value = counter[i]; + if (value != 0 && mask.test(BlockTypes.states[i])) { + total += value; + } + } + return total; + } + + public int getTotal() { + int total = 0; + for (int value : counter) total += value; + return total; + } + + public List> getDistribution() { + final List> distribution = new ArrayList<>(); + for (int i = 0; i < counter.length; i++) { + final int count = counter[i]; + if (count != 0) { + distribution.add(new Countable<>(BlockTypes.states[i], count)); + } + } + Collections.sort(distribution); + return distribution; + } + + public List> getTypeDistribution() { + final List> distribution = new ArrayList<>(); + int[] typeCounter = new int[BlockTypes.values.length]; + for (int i = 0; i < counter.length; i++) { + final int count = counter[i]; + if (count != 0) { + BlockState state = BlockTypes.states[i]; + typeCounter[state.getBlockType().getInternalId()] += count; + } + } + for (int i = 0; i < typeCounter.length; i++) { + final int count = typeCounter[i]; + if (count != 0) { + distribution.add(new Countable<>(BlockTypes.values[i], count)); + } + } + Collections.sort(distribution); + return distribution; + } + + public void print(final Actor actor, final long size) { + for (final Countable c : getDistribution()) { + final String name = c.getID().toString(); + final String str = String.format("%-7s (%.3f%%) %s", + String.valueOf(c.getAmount()), + c.getAmount() / (double) size * 100, + name); + actor.print(BBC.getPrefix() + str); + } + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/ForkedFilter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/ForkedFilter.java new file mode 100644 index 000000000..6118c4dea --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/ForkedFilter.java @@ -0,0 +1,48 @@ +package com.boydti.fawe.beta.filters; + +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.FilterBlock; +import com.boydti.fawe.config.BBC; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.util.Countable; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public abstract class ForkedFilter> implements Filter { + protected final Map children; + + public ForkedFilter(T root) { + if (root != null) { + children = root.children; + } else { + children = new ConcurrentHashMap<>(); + children.put(Thread.currentThread(), (T) this); + } + } + + @Override + public final Filter fork() { + return children.computeIfAbsent(Thread.currentThread(), thread -> init()); + } + + public abstract T init(); + + @Override + public void join() { + for (Map.Entry entry : children.entrySet()) { + T filter = entry.getValue(); + if (filter != this) { + join(filter); + } + } + children.clear(); + } + + public abstract void join(T filter); +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/SetFilter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/SetFilter.java new file mode 100644 index 000000000..841defd43 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/SetFilter.java @@ -0,0 +1,18 @@ +package com.boydti.fawe.beta.filters; + +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.FilterBlock; +import com.sk89q.worldedit.world.block.BlockState; + +public class SetFilter implements Filter { + private final BlockState state; + + public SetFilter(final BlockState state) { + this.state = state; + } + + @Override + public void applyBlock(final FilterBlock block) { + block.setBlock(state); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/DelegateChunkSet.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/DelegateChunkSet.java new file mode 100644 index 000000000..6b224de56 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/DelegateChunkSet.java @@ -0,0 +1,113 @@ +package com.boydti.fawe.beta.implementation; + +import com.boydti.fawe.beta.IChunkSet; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import javax.annotation.Nullable; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +public interface DelegateChunkSet extends IChunkSet { + IChunkSet getParent(); + + @Override + default boolean setBiome(int x, int y, int z, BiomeType biome) { + return getParent().setBiome(x, y, z, biome); + } + + @Override + default boolean setBlock(int x, int y, int z, BlockStateHolder holder) { + return getParent().setBlock(x, y, z, holder); + } + + @Override + default boolean isEmpty() { + return getParent().isEmpty(); + } + + @Override + default void setTile(int x, int y, int z, CompoundTag tile) { + getParent().setTile(x, y, z, tile); + } + + @Override + default void setEntity(CompoundTag tag) { + getParent().setEntity(tag); + } + + @Override + default void removeEntity(UUID uuid) { + getParent().removeEntity(uuid); + } + + @Override + default BlockState getBlock(int x, int y, int z) { + return getParent().getBlock(x, y, z); + } + + @Override + default char[] getArray(int layer) { + return getParent().getArray(layer); + } + + @Override + default BiomeType[] getBiomes() { + return getParent().getBiomes(); + } + + @Override + default Map getTiles() { + return getParent().getTiles(); + } + + @Override + default Set getEntities() { + return getParent().getEntities(); + } + + @Override + default Set getEntityRemoves() { + return getParent().getEntityRemoves(); + } + + @Override + default IChunkSet reset() { + IChunkSet parent = getParent(); + parent.reset(); + return parent; + } + + @Override + @Nullable + default Operation commit() { + return getParent().commit(); + } + + @Override + default boolean hasSection(int layer) { + return getParent().hasSection(layer); + } + + @Override + default boolean trim(boolean aggressive) { + return getParent().trim(aggressive); + } + + @Override + default > boolean setBlock(BlockVector3 position, T block) throws WorldEditException { + return getParent().setBlock(position, block); + } + + @Override + default boolean setBiome(BlockVector2 position, BiomeType biome) { + return getParent().setBiome(position, biome); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/IQueueWrapper.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/IQueueWrapper.java new file mode 100644 index 000000000..8c4957ce2 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/IQueueWrapper.java @@ -0,0 +1,9 @@ +package com.boydti.fawe.beta.implementation; + +import com.boydti.fawe.beta.IQueueExtent; + +public interface IQueueWrapper { + default IQueueExtent wrapQueue(IQueueExtent queue) { + return queue; + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/MultiThreadedQueue.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/MultiThreadedQueue.java new file mode 100644 index 000000000..e571306ac --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/MultiThreadedQueue.java @@ -0,0 +1,152 @@ +package com.boydti.fawe.beta.implementation; + +import com.boydti.fawe.beta.ChunkFilterBlock; +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IQueueExtent; +import com.boydti.fawe.beta.filters.CountFilter; +import com.boydti.fawe.beta.filters.DistrFilter; +import com.boydti.fawe.config.Settings; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Countable; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; + +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ForkJoinTask; + +public class MultiThreadedQueue extends AbstractDelegateExtent implements IQueueWrapper { + private final World world; + private final QueueHandler handler; + + protected MultiThreadedQueue(QueueHandler handler, World world) { + super(handler.getQueue(world)); + this.world = world; + this.handler = handler; + } + + public IQueueExtent getQueue() { + return handler.getQueue(this.world); + } + + public T apply(final Region region, final T filter) { + // The chunks positions to iterate over + final Set chunks = region.getChunks(); + final Iterator chunksIter = chunks.iterator(); + + // Get a pool, to operate on the chunks in parallel + final int size = Math.min(chunks.size(), Settings.IMP.QUEUE.PARALLEL_THREADS); + final ForkJoinTask[] tasks = new ForkJoinTask[size]; + for (int i = 0; i < size; i++) { + tasks[i] = handler.submit(new Runnable() { + @Override + public void run() { + final Filter newFilter = filter.fork(); + // Create a chunk that we will reuse/reset for each operation + final IQueueExtent queue = wrapQueue(getQueue()); + synchronized (queue) { + ChunkFilterBlock block = null; + + while (true) { + // Get the next chunk posWeakChunk + final int X, Z; + synchronized (chunksIter) { + if (!chunksIter.hasNext()) break; + final BlockVector2 pos = chunksIter.next(); + X = pos.getX(); + Z = pos.getZ(); + } + if (!newFilter.appliesChunk(X, Z)) { + continue; + } + IChunk chunk = queue.getCachedChunk(X, Z); + // Initialize + chunk.init(queue, X, Z); + + IChunk newChunk = newFilter.applyChunk(chunk, region); + if (newChunk != null) { + chunk = newChunk; + if (block == null) block = queue.initFilterBlock(); + chunk.filterBlocks(newFilter, block, region); + } + queue.submit(chunk); + } + queue.flush(); + } + } + }); + } + // Join filters + for (int i = 0; i < tasks.length; i++) { + final ForkJoinTask task = tasks[i]; + if (task != null) { + task.quietlyJoin(); + } + } + filter.join(); + return filter; + } + + public int getChanges() { + return -1; + } + + @Override + public int countBlocks(final Region region, final Mask searchMask) { + return + // Apply a filter over a region + apply(region, searchMask + .toFilter(new CountFilter())) // Adapt the mask to a filter which counts + .getParent() // Get the counter of this mask + .getTotal(); // Get the total from the counter + } + + @Override + public > int setBlocks(Region region, B block) throws MaxChangedBlocksException { + apply(region, block); + return getChanges(); + } + + @Override + public int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException { + apply(region, pattern); + return getChanges(); + } + + @Override + public int setBlocks(Set vset, Pattern pattern) { + if (vset instanceof Region) { + setBlocks((Region) vset, pattern); + } + for (BlockVector3 blockVector3 : vset) { + pattern.apply(this, blockVector3, blockVector3); + } + return getChanges(); + } + + @Override + public int replaceBlocks(Region region, Mask mask, Pattern pattern) throws MaxChangedBlocksException { + apply(region, mask.toFilter(pattern)); + return getChanges(); + } + + @Override + public List> getBlockDistributionWithData(Region region) { + return apply(region, new DistrFilter()).getDistribution(); + } + + @Override + public List> getBlockDistribution(Region region) { + return apply(region, new DistrFilter()).getTypeDistribution(); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java new file mode 100644 index 000000000..c323463f0 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java @@ -0,0 +1,210 @@ +package com.boydti.fawe.beta.implementation; + +import com.boydti.fawe.Fawe; +import com.boydti.fawe.FaweCache; +import com.boydti.fawe.beta.ChunkFilterBlock; +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IQueueExtent; +import com.boydti.fawe.beta.Trimable; +import com.boydti.fawe.config.Settings; +import com.boydti.fawe.object.collection.IterableThreadLocal; +import com.boydti.fawe.util.MemUtil; +import com.boydti.fawe.util.SetQueue; +import com.boydti.fawe.util.TaskManager; +import com.boydti.fawe.wrappers.WorldWrapper; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.MutableBlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.World; + +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * Class which handles all the queues {@link IQueueExtent} + */ +public abstract class QueueHandler implements Trimable, Runnable { + private ForkJoinPool forkJoinPoolPrimary = new ForkJoinPool(); + private ForkJoinPool forkJoinPoolSecondary = new ForkJoinPool(); + private ThreadPoolExecutor blockingExecutor = FaweCache.newBlockingExecutor(); + private ConcurrentLinkedQueue syncTasks = new ConcurrentLinkedQueue(); + + private Map> chunkCache = new HashMap<>(); + private IterableThreadLocal queuePool = new IterableThreadLocal() { + @Override + public IQueueExtent init() { + return create(); + } + }; + + public QueueHandler() { + TaskManager.IMP.repeat(this, 1); + } + + /** + * Used to calculate elapsed time in milliseconds and ensure block placement doesn't lag the server + */ + private long last; + private long allocate = 50; + private double targetTPS = 18; + + @Override + public void run() { + if (!Fawe.isMainThread()) { + throw new IllegalStateException("Not main thread"); + } + if (!syncTasks.isEmpty()) { + long now = System.currentTimeMillis(); + targetTPS = 18 - Math.max(Settings.IMP.QUEUE.EXTRA_TIME_MS * 0.05, 0); + long diff = (50 + this.last) - (this.last = now); + long absDiff = Math.abs(diff); + if (diff == 0) { + allocate = Math.min(50, allocate + 1); + } else if (diff < 0) { + allocate = Math.max(5, allocate + diff); + } else if (!Fawe.get().getTimer().isAbove(targetTPS)) { + allocate = Math.max(5, allocate - 1); + } + long currentAllocate = allocate - absDiff; + + if (!MemUtil.isMemoryFree()) { + // TODO reduce mem usage + } + + long taskAllocate = currentAllocate; + boolean wait = false; + do { + Runnable task = syncTasks.poll(); + if (task == null) { + if (wait) { + synchronized (syncTasks) { + try { + syncTasks.wait(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + task = syncTasks.poll(); + wait = false; + } else { + break; + } + } + if (task != null) { + task.run(); + wait = true; + } + } while (System.currentTimeMillis() - now < taskAllocate); + } + while (!syncTasks.isEmpty()) { + final FutureTask task = syncTasks.poll(); + if (task != null) task.run(); + } + } + + public Future async(final Runnable run, final T value) { + return forkJoinPoolSecondary.submit(run, value); + } + + public Future async(final Callable call) { + return forkJoinPoolSecondary.submit(call); + } + + public ForkJoinTask submit(final Runnable call) { + return forkJoinPoolPrimary.submit(call); + } + + public Future sync(final Runnable run, final T value) { + final FutureTask result = new FutureTask<>(run, value); + syncTasks.add(result); + notifySync(); + return result; + } + + public Future sync(final Runnable run) { + final FutureTask result = new FutureTask<>(run, null); + syncTasks.add(result); + notifySync(); + return result; + } + + public Future sync(final Callable call) { + final FutureTask result = new FutureTask<>(call); + syncTasks.add(result); + notifySync(); + return result; + } + + private void notifySync() { + synchronized (syncTasks) { + syncTasks.notifyAll(); + } + } + + public > T submit(final IChunk chunk) { + if (MemUtil.isMemoryFree()) { +// return (T) forkJoinPoolSecondary.submit(chunk); + } + return (T) blockingExecutor.submit(chunk); + } + + /** + * Get or create the WorldChunkCache for a world + * @param world + * @return + */ + public WorldChunkCache getOrCreate(World world) { + world = WorldWrapper.unwrap(world); + + synchronized (chunkCache) { + final WeakReference ref = chunkCache.get(world); + if (ref != null) { + final WorldChunkCache cached = ref.get(); + if (cached != null) { + return cached; + } + } + final WorldChunkCache created = new WorldChunkCache(world); + chunkCache.put(world, new WeakReference<>(created)); + return created; + } + } + + public abstract IQueueExtent create(); + + public IQueueExtent getQueue(final World world) { + final IQueueExtent queue = queuePool.get(); + queue.init(getOrCreate(world)); + return queue; + } + + @Override + public boolean trim(final boolean aggressive) { + boolean result = true; + synchronized (chunkCache) { + final Iterator>> iter = chunkCache.entrySet().iterator(); + while (iter.hasNext()) { + final Map.Entry> entry = iter.next(); + final WeakReference value = entry.getValue(); + final WorldChunkCache cache = value.get(); + if (cache == null || cache.size() == 0 || cache.trim(aggressive)) { + iter.remove(); + continue; + } + result = false; + } + } + return result; + } +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SimpleCharQueueExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SimpleCharQueueExtent.java new file mode 100644 index 000000000..b341c7021 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SimpleCharQueueExtent.java @@ -0,0 +1,12 @@ +package com.boydti.fawe.beta.implementation; + +import com.boydti.fawe.beta.CharFilterBlock; +import com.boydti.fawe.beta.ChunkFilterBlock; +import com.boydti.fawe.beta.FilterBlock; + +public abstract class SimpleCharQueueExtent extends SingleThreadQueueExtent { + @Override + public ChunkFilterBlock initFilterBlock() { + return new CharFilterBlock(this); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SingleThreadQueueExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SingleThreadQueueExtent.java new file mode 100644 index 000000000..522987383 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SingleThreadQueueExtent.java @@ -0,0 +1,254 @@ +package com.boydti.fawe.beta.implementation; + +import com.boydti.fawe.Fawe; +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.IQueueExtent; +import com.boydti.fawe.beta.implementation.holder.ReferenceChunk; +import com.boydti.fawe.config.Settings; +import com.boydti.fawe.util.MathMan; +import com.boydti.fawe.util.MemUtil; +import com.google.common.util.concurrent.Futures; +import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; + +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.function.Supplier; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Single threaded implementation for IQueueExtent (still abstract) + * - Does not implement creation of chunks (that has to implemented by the platform e.g. Bukkit) + * + * This queue is reusable {@link #init(WorldChunkCache)} + */ +public abstract class SingleThreadQueueExtent implements IQueueExtent { + private WorldChunkCache cache; + private Thread currentThread; + private ConcurrentLinkedQueue submissions = new ConcurrentLinkedQueue<>(); + + /** + * Safety check to ensure that the thread being used matches the one being initialized on + * - Can be removed later + */ + private void checkThread() { + if (Thread.currentThread() != currentThread && currentThread != null) { + throw new UnsupportedOperationException("This class must be used from a single thread. Use multiple queues for concurrent operations"); + } + } + + @Override + public IChunkGet getCachedGet(int X, int Z, Supplier supplier) { + return cache.get(MathMan.pairInt(X, Z), supplier); + } + + /** + * Reset the queue + */ + protected synchronized void reset() { + checkThread(); + cache = null; + if (!chunks.isEmpty()) { + CHUNK_POOL.addAll(chunks.values()); + chunks.clear(); + } + lastChunk = null; + lastPair = Long.MAX_VALUE; + currentThread = null; + } + + /** + * Initialize the queue + * @param cache + */ + @Override + public synchronized void init(final WorldChunkCache cache) { + if (this.cache != null) { + reset(); + } + currentThread = Thread.currentThread(); + checkNotNull(cache); + this.cache = cache; + } + + // Last access pointers + private IChunk lastChunk; + private long lastPair = Long.MAX_VALUE; + // Chunks currently being queued / worked on + private final Long2ObjectLinkedOpenHashMap chunks = new Long2ObjectLinkedOpenHashMap<>(); + // Pool discarded chunks for reuse (can safely be cleared by another thread) + private static final ConcurrentLinkedQueue CHUNK_POOL = new ConcurrentLinkedQueue<>(); + + public void returnToPool(final IChunk chunk) { + CHUNK_POOL.add(chunk); + } + + @Override + public > T submit(final IChunk chunk) { + if (lastChunk == chunk) { + lastPair = Long.MAX_VALUE; + lastChunk = null; + } + final long index = MathMan.pairInt(chunk.getX(), chunk.getZ()); + chunks.remove(index, chunk); + return submitUnchecked(chunk); + } + + /** + * Submit without first checking that it has been removed from the chunk map + * @param chunk + * @param + * @return + */ + private > T submitUnchecked(final IChunk chunk) { + if (chunk.isEmpty()) { + CHUNK_POOL.add(chunk); + return (T) (Future) Futures.immediateFuture(null); + } + + if (Fawe.isMainThread()) { + return chunk.call(); + } + + return Fawe.get().getQueueHandler().submit(chunk); + } + + @Override + public synchronized boolean trim(final boolean aggressive) { + // TODO trim individial chunk sections + CHUNK_POOL.clear(); + if (Thread.currentThread() == currentThread) { + lastChunk = null; + lastPair = Long.MAX_VALUE; + return chunks.isEmpty(); + } + if (!submissions.isEmpty()) { + if (aggressive) { + pollSubmissions(0, aggressive); + } else { + pollSubmissions(Settings.IMP.QUEUE.PARALLEL_THREADS, aggressive); + } + } + synchronized (this) { + return currentThread == null; + } + } + + /** + * Get a new IChunk from either the pool, or create a new one
+ * + Initialize it at the coordinates + * @param X + * @param Z + * @return IChunk + */ + private IChunk poolOrCreate(final int X, final int Z) { + IChunk next = CHUNK_POOL.poll(); + if (next == null) { + next = create(false); + } + next.init(this, X, Z); + return next; + } + + @Override + public final IChunk getCachedChunk(final int X, final int Z) { + final long pair = (((long) X) << 32) | (Z & 0xffffffffL); + if (pair == lastPair) { + return lastChunk; + } + + IChunk chunk = chunks.get(pair); + if (chunk instanceof ReferenceChunk) { + chunk = ((ReferenceChunk) (chunk)).getParent(); + } + if (chunk != null) { + lastPair = pair; + lastChunk = chunk; + } + if (chunk != null) return chunk; + + checkThread(); + final int size = chunks.size(); + final boolean lowMem = MemUtil.isMemoryLimited(); + if (lowMem || size > Settings.IMP.QUEUE.TARGET_SIZE) { + chunk = chunks.removeFirst(); + final Future future = submitUnchecked(chunk); + if (future != null && !future.isDone()) { + final int targetSize; + if (lowMem) { + targetSize = Settings.IMP.QUEUE.PARALLEL_THREADS; + } else { + targetSize = Settings.IMP.QUEUE.TARGET_SIZE; + } + pollSubmissions(targetSize, true); + submissions.add(future); + } + } + chunk = poolOrCreate(X, Z); + chunk = wrap(chunk); + + chunks.put(pair, chunk); + lastPair = pair; + lastChunk = chunk; + + return chunk; + } + + private void pollSubmissions(final int targetSize, final boolean aggressive) { + final int overflow = submissions.size() - targetSize; + if (aggressive) { + for (int i = 0; i < overflow; i++) { + Future first = submissions.poll(); + try { + while ((first = (Future) first.get()) != null) ; + } catch (final InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + } + } else { + for (int i = 0; i < overflow; i++) { + Future next = submissions.peek(); + while (next != null) { + if (next.isDone()) { + try { + next = (Future) next.get(); + } catch (final InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + } else { + return; + } + } + submissions.poll(); + } + } + } + + @Override + public synchronized void flush() { + checkThread(); + if (!chunks.isEmpty()) { + if (MemUtil.isMemoryLimited()) { + for (final IChunk chunk : chunks.values()) { + final Future future = submitUnchecked(chunk); + if (future != null && !future.isDone()) { + pollSubmissions(Settings.IMP.QUEUE.PARALLEL_THREADS, true); + submissions.add(future); + } + } + } else { + for (final IChunk chunk : chunks.values()) { + final Future future = submitUnchecked(chunk); + if (future != null && !future.isDone()) { + submissions.add(future); + } + } + } + chunks.clear(); + } + pollSubmissions(0, true); + reset(); + } +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/WorldChunkCache.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/WorldChunkCache.java new file mode 100644 index 000000000..243bc23c5 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/WorldChunkCache.java @@ -0,0 +1,72 @@ +package com.boydti.fawe.beta.implementation; + +import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.Trimable; +import com.sk89q.worldedit.world.World; +import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.objects.ObjectIterator; + +import java.lang.ref.WeakReference; +import java.util.function.Supplier; + +/** + * IGetBlocks may be cached by the WorldChunkCache so that it can be used between multiple IQueueExtents + * - avoids conversion between palette and raw data on every block get + */ +public class WorldChunkCache implements Trimable { + protected final Long2ObjectLinkedOpenHashMap> getCache; + private final World world; + + protected WorldChunkCache(final World world) { + this.world = world; + this.getCache = new Long2ObjectLinkedOpenHashMap<>(); + } + + public World getWorld() { + return world; + } + + public synchronized int size() { + return getCache.size(); + } + + /** + * Get or create the IGetBlocks + * @param index chunk index {@link com.boydti.fawe.util.MathMan#pairInt(int, int)} + * @param provider used to create if it isn't already cached + * @return cached IGetBlocks + */ + public synchronized IChunkGet get(final long index, final Supplier provider) { + final WeakReference ref = getCache.get(index); + if (ref != null) { + final IChunkGet blocks = ref.get(); + if (blocks != null) return blocks; + } + final IChunkGet blocks = provider.get(); + getCache.put(index, new WeakReference<>(blocks)); + return blocks; + } + + @Override + public synchronized boolean trim(final boolean aggressive) { + boolean result = true; + if (!getCache.isEmpty()) { + final ObjectIterator>> iter = getCache.long2ObjectEntrySet().fastIterator(); + while (iter.hasNext()) { + final Long2ObjectMap.Entry> entry = iter.next(); + final WeakReference value = entry.getValue(); + final IChunkGet igb = value.get(); + if (igb == null) iter.remove(); + else { + result = false; + if (!aggressive) return result; + synchronized (igb) { + igb.trim(aggressive); + } + } + } + } + return result; + } +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java new file mode 100644 index 000000000..1c50695f2 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java @@ -0,0 +1,114 @@ +package com.boydti.fawe.beta.implementation.blocks; + +import com.boydti.fawe.beta.IBlocks; +import com.boydti.fawe.beta.IChunkSet; + +public class CharBlocks implements IBlocks { + public final char[][] blocks; + public final Section[] sections; + + public CharBlocks(CharBlocks other) { + this.blocks = other.blocks; + this.sections = other.sections; + } + + public CharBlocks() { + blocks = new char[16][]; + sections = new Section[16]; + for (int i = 0; i < 16; i++) sections[i] = EMPTY; + } + + @Override + public boolean trim(final boolean aggressive) { + boolean result = true; + for (int i = 0; i < 16; i++) { + if (sections[i] == EMPTY) { + blocks[i] = null; + } else { + result = false; + } + } + return result; + } + + @Override + public IChunkSet reset() { + for (int i = 0; i < 16; i++) sections[i] = EMPTY; + return null; + } + + public void reset(final int layer) { + sections[layer] = EMPTY; + } + + public char[] load(final int layer) { + return new char[4096]; + } + + public char[] load(final int layer, final char[] data) { + for (int i = 0; i < 4096; i++) data[i] = 0; + return data; + } + + @Override + public boolean hasSection(final int layer) { + return sections[layer] == FULL; + } + + public char get(final int x, final int y, final int z) { + final int layer = y >> 4; + final int index = ((y & 15) << 8) | (z << 4) | (x & 15); + return sections[layer].get(this, layer, index); + } + + public void set(final int x, final int y, final int z, final char value) { + final int layer = y >> 4; + final int index = ((y & 15) << 8) | (z << 4) | (x & 15); + set(layer, index, value); + } + + public final char get(final int layer, final int index) { + return sections[layer].get(this, layer, index); + } + + public final void set(final int layer, final int index, final char value) { + sections[layer].set(this, layer, index, value); + } + + /* + Section + */ + + public static abstract class Section { + public abstract char[] get(CharBlocks blocks, int layer); + + public final char get(final CharBlocks blocks, final int layer, final int index) { + return get(blocks, layer)[index]; + } + + public final void set(final CharBlocks blocks, final int layer, final int index, final char value) { + get(blocks, layer)[index] = value; + } + } + + public static final Section EMPTY = new Section() { + @Override + public final char[] get(final CharBlocks blocks, final int layer) { + blocks.sections[layer] = FULL; + char[] arr = blocks.blocks[layer]; + if (arr == null) { + arr = blocks.blocks[layer] = blocks.load(layer); + } else { + blocks.blocks[layer] = blocks.load(layer, arr); + } + return arr; + } + }; + + public static final Section FULL = new Section() { + @Override + public final char[] get(final CharBlocks blocks, final int layer) { + return blocks.blocks[layer]; + } + }; +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java new file mode 100644 index 000000000..7c5dcf613 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java @@ -0,0 +1,34 @@ +package com.boydti.fawe.beta.implementation.blocks; + +import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.IChunkSet; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; + +public abstract class CharGetBlocks extends CharBlocks implements IChunkGet { + @Override + public BaseBlock getFullBlock(final int x, final int y, final int z) { + return BlockTypes.states[get(x, y, z)].toBaseBlock(); + } + + @Override + public BlockState getBlock(final int x, final int y, final int z) { + return BlockTypes.states[get(x, y, z)]; + } + + @Override + public boolean trim(final boolean aggressive) { + for (int i = 0; i < 16; i++) { + sections[i] = EMPTY; + blocks[i] = null; + } + return true; + } + + @Override + public IChunkSet reset() { + super.reset(); + return null; + } +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java new file mode 100644 index 000000000..23db45a27 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java @@ -0,0 +1,124 @@ +package com.boydti.fawe.beta.implementation.blocks; + +import com.boydti.fawe.beta.IChunkSet; +import com.boydti.fawe.util.MathMan; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +public class CharSetBlocks extends CharBlocks implements IChunkSet { + public BiomeType[] biomes; + public HashMap tiles; + public HashSet entities; + public HashSet entityRemoves; + + public CharSetBlocks(CharBlocks other) { + super(other); + if (other instanceof CharSetBlocks) { + + } + } + + public CharSetBlocks() { + + } + + @Override + public char[] getArray(int layer) { + return sections[layer].get(this, layer); + } + + @Override + public BiomeType[] getBiomes() { + return biomes; + } + + @Override + public Map getTiles() { + return tiles; + } + + @Override + public Set getEntities() { + return entities; + } + + @Override + public Set getEntityRemoves() { + return entityRemoves; + } + + @Override + public boolean setBiome(final int x, final int y, final int z, final BiomeType biome) { + if (biomes == null) { + biomes = new BiomeType[256]; + } + biomes[x + (z << 4)] = biome; + return true; + } + + @Override + public BlockState getBlock(int x, int y, int z) { + return BlockTypes.states[get(x, y, z)]; + } + + @Override + public boolean setBlock(final int x, final int y, final int z, final BlockStateHolder holder) { + set(x, y, z, holder.getOrdinalChar()); + return true; + } + + @Override + public void setTile(final int x, final int y, final int z, final CompoundTag tile) { + if (tiles == null) { + tiles = new HashMap<>(); + } + final short pair = MathMan.tripleBlockCoord(x, y, z); + tiles.put(pair, tile); + } + + @Override + public void setEntity(final CompoundTag tag) { + if (entities == null) { + entities = new HashSet<>(); + } + entities.add(tag); + } + + @Override + public void removeEntity(final UUID uuid) { + if (entityRemoves == null) { + entityRemoves = new HashSet<>(); + } + entityRemoves.add(uuid); + } + + @Override + public boolean isEmpty() { + if (biomes != null) return false; + for (int i = 0; i < 16; i++) { + if (hasSection(i)) { + return false; + } + } + return true; + } + + @Override + public IChunkSet reset() { + biomes = null; + tiles = null; + entities = null; + entityRemoves = null; + super.reset(); + return null; + } +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java new file mode 100644 index 000000000..794065f2a --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java @@ -0,0 +1,313 @@ +package com.boydti.fawe.beta.implementation.holder; + +import com.boydti.fawe.beta.ChunkFilterBlock; +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.FilterBlockMask; +import com.boydti.fawe.beta.Flood; +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.IChunkSet; +import com.boydti.fawe.beta.IQueueExtent; +import com.boydti.fawe.beta.implementation.SingleThreadQueueExtent; +import com.boydti.fawe.beta.implementation.WorldChunkCache; +import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks; +import com.boydti.fawe.util.MathMan; +import com.sk89q.worldedit.math.MutableBlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import javax.annotation.Nullable; +import java.util.function.Supplier; + +/** + * Abstract IChunk class that implements basic get/set blocks + */ +public abstract class ChunkHolder implements IChunk, Supplier { + private IChunkGet get; + private IChunkSet set; + private IBlockDelegate delegate; + private IQueueExtent extent; + private int X,Z; + + public ChunkHolder() { + this.delegate = NULL; + } + + public ChunkHolder(final IBlockDelegate delegate) { + this.delegate = delegate; + } + + @Override + public void flood(Flood flood, FilterBlockMask mask, ChunkFilterBlock block) { +// block.flood(get, set, mask, block, ); + } + + @Override + public void filterBlocks(final Filter filter, ChunkFilterBlock block, @Nullable Region region) { + final IChunkGet get = getOrCreateGet(); + final IChunkSet set = getOrCreateSet(); + try { + if (region != null) { + region.filter(this, filter, block, get, set); + } else { + block = block.init(X, Z, get); + for (int layer = 0; layer < 16; layer++) { + if (!get.hasSection(layer) || !filter.appliesLayer(this, layer)) continue; + block.init(get, set, layer); + block.filter(filter); + } + } + } finally { + filter.finishChunk(this); + } + } + + @Override + public boolean trim(final boolean aggressive) { + if (set != null) { + final boolean result = set.trim(aggressive); + if (result) { + delegate = NULL; + get = null; + set = null; + return true; + } + } + if (aggressive) { + get = null; + if (delegate == BOTH) { + delegate = SET; + } else if (delegate == GET) { + delegate = NULL; + } + } else { + get.trim(false); + } + return false; + } + + @Override + public boolean isEmpty() { + return set == null || set.isEmpty(); + } + + public final IChunkGet getOrCreateGet() { + if (get == null) get = newGet(); + return get; + } + + public final IChunkSet getOrCreateSet() { + if (set == null) set = set(); + return set; + } + + public IChunkSet set() { + return new CharSetBlocks(); + } + + private IChunkGet newGet() { + if (extent instanceof SingleThreadQueueExtent) { + IChunkGet newGet = extent.getCachedGet(X, Z, this); + if (newGet != null) { + return newGet; + } + } + return get(); + } + + @Override + public void init(final IQueueExtent extent, final int X, final int Z) { + this.extent = extent; + this.X = X; + this.Z = Z; + if (set != null) { + set.reset(); + delegate = SET; + } else { + delegate = NULL; + } + get = null; + } + + public IQueueExtent getExtent() { + return extent; + } + + @Override + public int getX() { + return X; + } + + @Override + public int getZ() { + return Z; + } + + @Override + public boolean setBiome(final int x, final int y, final int z, final BiomeType biome) { + return delegate.setBiome(this, x, y, z, biome); + } + + @Override + public boolean setBlock(final int x, final int y, final int z, final BlockStateHolder block) { + return delegate.setBlock(this, x, y, z, block); + } + + @Override + public BiomeType getBiome(final int x, final int z) { + return delegate.getBiome(this, x, z); + } + + @Override + public BlockState getBlock(final int x, final int y, final int z) { + return delegate.getBlock(this, x, y, z); + } + + @Override + public BaseBlock getFullBlock(final int x, final int y, final int z) { + return delegate.getFullBlock(this, x, y, z); + } + + public interface IBlockDelegate { + boolean setBiome(final ChunkHolder chunk, final int x, final int y, final int z, final BiomeType biome); + + boolean setBlock(final ChunkHolder chunk, final int x, final int y, final int z, final BlockStateHolder holder); + + BiomeType getBiome(final ChunkHolder chunk, final int x, final int z); + + BlockState getBlock(final ChunkHolder chunk, final int x, final int y, final int z); + + BaseBlock getFullBlock(final ChunkHolder chunk, final int x, final int y, final int z); + } + + public static final IBlockDelegate NULL = new IBlockDelegate() { + @Override + public boolean setBiome(final ChunkHolder chunk, final int x, final int y, final int z, final BiomeType biome) { + chunk.getOrCreateSet(); + chunk.delegate = SET; + return chunk.setBiome(x, y, z, biome); + } + + @Override + public boolean setBlock(final ChunkHolder chunk, final int x, final int y, final int z, final BlockStateHolder block) { + chunk.getOrCreateSet(); + chunk.delegate = SET; + return chunk.setBlock(x, y, z, block); + } + + @Override + public BiomeType getBiome(final ChunkHolder chunk, final int x, final int z) { + chunk.getOrCreateGet(); + chunk.delegate = GET; + return chunk.getBiome(x, z); + } + + @Override + public BlockState getBlock(final ChunkHolder chunk, final int x, final int y, final int z) { + chunk.getOrCreateGet(); + chunk.delegate = GET; + return chunk.getBlock(x, y, z); + } + + @Override + public BaseBlock getFullBlock(final ChunkHolder chunk, final int x, final int y, final int z) { + chunk.getOrCreateGet(); + chunk.delegate = GET; + return chunk.getFullBlock(x, y, z); + } + }; + + public static final IBlockDelegate GET = new IBlockDelegate() { + @Override + public boolean setBiome(final ChunkHolder chunk, final int x, final int y, final int z, final BiomeType biome) { + chunk.getOrCreateSet(); + chunk.delegate = BOTH; + return chunk.setBiome(x, y, z, biome); + } + + @Override + public boolean setBlock(final ChunkHolder chunk, final int x, final int y, final int z, final BlockStateHolder block) { + chunk.getOrCreateSet(); + chunk.delegate = BOTH; + return chunk.setBlock(x, y, z, block); + } + + @Override + public BiomeType getBiome(final ChunkHolder chunk, final int x, final int z) { + return chunk.get.getBiomeType(x, z); + } + + @Override + public BlockState getBlock(final ChunkHolder chunk, final int x, final int y, final int z) { + return chunk.get.getBlock(x, y, z); + } + + @Override + public BaseBlock getFullBlock(final ChunkHolder chunk, final int x, final int y, final int z) { + return chunk.get.getFullBlock(x, y, z); + } + }; + + public static final IBlockDelegate SET = new IBlockDelegate() { + @Override + public boolean setBiome(final ChunkHolder chunk, final int x, final int y, final int z, final BiomeType biome) { + return chunk.set.setBiome(x, y, z, biome); + } + + @Override + public boolean setBlock(final ChunkHolder chunk, final int x, final int y, final int z, final BlockStateHolder block) { + return chunk.set.setBlock(x, y, z, block); + } + + @Override + public BiomeType getBiome(final ChunkHolder chunk, final int x, final int z) { + chunk.getOrCreateGet(); + chunk.delegate = BOTH; + return chunk.getBiome(x, z); + } + + @Override + public BlockState getBlock(final ChunkHolder chunk, final int x, final int y, final int z) { + chunk.getOrCreateGet(); + chunk.delegate = BOTH; + return chunk.getBlock(x, y, z); + } + + @Override + public BaseBlock getFullBlock(final ChunkHolder chunk, final int x, final int y, final int z) { + chunk.getOrCreateGet(); + chunk.delegate = BOTH; + return chunk.getFullBlock(x, y, z); + } + }; + + public static final IBlockDelegate BOTH = new IBlockDelegate() { + @Override + public boolean setBiome(final ChunkHolder chunk, final int x, final int y, final int z, final BiomeType biome) { + return chunk.set.setBiome(x, y, z, biome); + } + + @Override + public boolean setBlock(final ChunkHolder chunk, final int x, final int y, final int z, final BlockStateHolder block) { + return chunk.set.setBlock(x, y, z, block); + } + + @Override + public BiomeType getBiome(final ChunkHolder chunk, final int x, final int z) { + return chunk.get.getBiomeType(x, z); + } + + @Override + public BlockState getBlock(final ChunkHolder chunk, final int x, final int y, final int z) { + return chunk.get.getBlock(x, y, z); + } + + @Override + public BaseBlock getFullBlock(final ChunkHolder chunk, final int x, final int y, final int z) { + return chunk.get.getFullBlock(x, y, z); + } + }; +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/DelegateChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/DelegateChunk.java new file mode 100644 index 000000000..88c6269db --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/DelegateChunk.java @@ -0,0 +1,33 @@ +package com.boydti.fawe.beta.implementation.holder; + +import com.boydti.fawe.beta.ChunkFilterBlock; +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.FilterBlock; +import com.boydti.fawe.beta.FilterBlockMask; +import com.boydti.fawe.beta.Flood; +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IDelegateChunk; +import com.sk89q.worldedit.math.MutableBlockVector3; +import com.sk89q.worldedit.regions.Region; + +import javax.annotation.Nullable; + +/** + * Implementation of IDelegateChunk + * @param + */ +public class DelegateChunk implements IDelegateChunk { + private T parent; + + public DelegateChunk(final T parent) { + this.parent = parent; + } + + public final T getParent() { + return parent; + } + + public final void setParent(final T parent) { + this.parent = parent; + } +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/FinalizedChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/FinalizedChunk.java new file mode 100644 index 000000000..ca599ae94 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/FinalizedChunk.java @@ -0,0 +1,31 @@ +package com.boydti.fawe.beta.implementation.holder; + +import com.boydti.fawe.beta.IQueueExtent; +import com.boydti.fawe.beta.IChunk; + +/** + * Used by {@link ReferenceChunk} to allow the chunk to be garbage collected + * - When the object is finalized, add it to the queue + */ +public class FinalizedChunk extends DelegateChunk { + private final IQueueExtent queueExtent; + + public FinalizedChunk(final IChunk parent, final IQueueExtent queueExtent) { + super(parent); + this.queueExtent = queueExtent; + } + + /** + * Submit the chunk to the queue + * @throws Throwable + */ + @Override + protected void finalize() throws Throwable { + if (getParent() != null) { + // TODO apply safely +// apply(); + setParent(null); + } + super.finalize(); + } +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ReferenceChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ReferenceChunk.java new file mode 100644 index 000000000..cb88a839e --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ReferenceChunk.java @@ -0,0 +1,28 @@ +package com.boydti.fawe.beta.implementation.holder; + +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IDelegateChunk; +import com.boydti.fawe.beta.IQueueExtent; + +import java.lang.ref.Reference; + +/** + * An IChunk may be wrapped by a ReferenceChunk if there is low memory
+ * A reference chunk stores a reference (for garbage collection purposes)
+ * - If it is garbage collected, the {@link FinalizedChunk} logic is run + */ +public abstract class ReferenceChunk implements IDelegateChunk { + private final Reference ref; + + public ReferenceChunk(final IChunk parent, final IQueueExtent queueExtent) { + this.ref = toRef(new FinalizedChunk(parent, queueExtent)); + } + + protected abstract Reference toRef(FinalizedChunk parent); + + @Override + public IChunk getParent() { + final FinalizedChunk finalized = ref.get(); + return finalized != null ? finalized.getParent() : null; + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/SoftChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/SoftChunk.java new file mode 100644 index 000000000..361b7083d --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/SoftChunk.java @@ -0,0 +1,22 @@ +package com.boydti.fawe.beta.implementation.holder; + +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IQueueExtent; + +import java.lang.ref.Reference; +import java.lang.ref.SoftReference; + +/** + * Soft reference implementation of {@link ReferenceChunk} + */ +public class SoftChunk extends ReferenceChunk { + + public SoftChunk(final IChunk parent, final IQueueExtent queueExtent) { + super(parent, queueExtent); + } + + @Override + protected Reference toRef(final FinalizedChunk parent) { + return new SoftReference<>(parent); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/WeakChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/WeakChunk.java new file mode 100644 index 000000000..a97c915d5 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/WeakChunk.java @@ -0,0 +1,21 @@ +package com.boydti.fawe.beta.implementation.holder; + +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IQueueExtent; + +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; + +/** + * Weak reference implementation of {@link ReferenceChunk} + */ +public class WeakChunk extends ReferenceChunk { + public WeakChunk(final IChunk parent, final IQueueExtent queueExtent) { + super(parent, queueExtent); + } + + @Override + protected Reference toRef(final FinalizedChunk parent) { + return new WeakReference<>(parent); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/command/FawePrimitiveBinding.java b/worldedit-core/src/main/java/com/boydti/fawe/command/FawePrimitiveBinding.java index 0a2c76534..c3800dfa5 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/command/FawePrimitiveBinding.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/command/FawePrimitiveBinding.java @@ -4,9 +4,9 @@ import com.boydti.fawe.Fawe; import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.extent.NullExtent; import com.boydti.fawe.object.extent.ResettableExtent; -import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.TextureUtil; import com.boydti.fawe.util.image.ImageUtil; + import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; @@ -30,23 +30,20 @@ import com.sk89q.worldedit.util.command.binding.Text; import com.sk89q.worldedit.util.command.binding.Validate; import com.sk89q.worldedit.util.command.parametric.ArgumentStack; import com.sk89q.worldedit.util.command.parametric.BindingBehavior; -import com.sk89q.worldedit.util.command.parametric.BindingHelper; import com.sk89q.worldedit.util.command.parametric.BindingMatch; import com.sk89q.worldedit.util.command.parametric.ParameterException; import com.sk89q.worldedit.world.World; + +import javax.annotation.Nullable; import java.awt.image.BufferedImage; -import java.io.File; -import java.io.IOException; import java.lang.annotation.Annotation; import java.net.URI; -import java.net.URL; -import javax.annotation.Nullable; public class FawePrimitiveBinding { @BindingMatch(type = {Long.class, long.class}, - behavior = BindingBehavior.CONSUMES, - consumedCount = 1, - provideModifiers = true) + behavior = BindingBehavior.CONSUMES, + consumedCount = 1, + provideModifiers = true) public Long getLong(ArgumentStack context, Annotation[] modifiers) throws ParameterException { try { Long v = Long.parseLong(context.next()); @@ -80,11 +77,15 @@ public class FawePrimitiveBinding { public class ImageUri { public final URI uri; private BufferedImage image; - public ImageUri(URI uri) { + + ImageUri(URI uri) { this.uri = uri; } + public BufferedImage load() throws ParameterException { - if (image != null) return image; + if (image != null) { + return image; + } return image = ImageUtil.load(uri); } } @@ -105,7 +106,9 @@ public class FawePrimitiveBinding { ) public TextureUtil getTexture(ArgumentStack context) { Actor actor = context.getContext().getLocals().get(Actor.class); - if (actor == null) return Fawe.get().getCachedTextureUtil(true, 0, 100); + if (actor == null) { + return Fawe.get().getCachedTextureUtil(true, 0, 100); + } LocalSession session = WorldEdit.getInstance().getSessionManager().get(actor); return session.getTextureUtil(); } @@ -117,12 +120,20 @@ public class FawePrimitiveBinding { ) public Extent getExtent(ArgumentStack context) throws ParameterException { Extent extent = context.getContext().getLocals().get(EditSession.class); - if (extent != null) return extent; + if (extent != null) { + return extent; + } extent = Request.request().getExtent(); - if (extent != null) return extent; + if (extent != null) { + return extent; + } Actor actor = context.getContext().getLocals().get(Actor.class); - if (actor == null) throw new ParameterException("No player to get a session for"); - if (!(actor instanceof Player)) throw new ParameterException("Caller is not a player"); + if (actor == null) { + throw new ParameterException("No player to get a session for"); + } + if (!(actor instanceof Player)) { + throw new ParameterException("Caller is not a player"); + } LocalSession session = WorldEdit.getInstance().getSessionManager().get(actor); EditSession editSession = session.createEditSession((Player) actor); editSession.enableQueue(); @@ -139,7 +150,7 @@ public class FawePrimitiveBinding { * @throws ParameterException on other error */ @BindingMatch(type = FawePlayer.class, - behavior = BindingBehavior.PROVIDES) + behavior = BindingBehavior.PROVIDES) public FawePlayer getFawePlayer(ArgumentStack context) throws ParameterException, InputParseException { Actor sender = context.getContext().getLocals().get(Actor.class); if (sender == null) { @@ -157,10 +168,12 @@ public class FawePrimitiveBinding { * @throws ParameterException on other error */ @BindingMatch(type = ResettableExtent.class, - behavior = BindingBehavior.PROVIDES) + behavior = BindingBehavior.PROVIDES) public ResettableExtent getResettableExtent(ArgumentStack context) throws ParameterException, InputParseException { String input = context.next(); - if (input.equalsIgnoreCase("#null")) return new NullExtent(); + if (input.equalsIgnoreCase("#null")) { + return new NullExtent(); + } DefaultTransformParser parser = Fawe.get().getTransformParser(); Actor actor = context.getContext().getLocals().get(Actor.class); ParserContext parserContext = new ParserContext(); @@ -178,17 +191,17 @@ public class FawePrimitiveBinding { /** * Gets a type from a {@link ArgumentStack}. * - * @param context the context - * @param text the text annotation + * @param context the context + * @param text the text annotation * @param modifiers a list of modifiers * @return the requested type * @throws ParameterException on error */ @BindingMatch(classifier = Text.class, - type = String.class, - behavior = BindingBehavior.CONSUMES, - consumedCount = -1, - provideModifiers = true) + type = String.class, + behavior = BindingBehavior.CONSUMES, + consumedCount = -1, + provideModifiers = true) public String getText(ArgumentStack context, Text text, Annotation[] modifiers) throws ParameterException { String v = context.remaining(); @@ -196,9 +209,9 @@ public class FawePrimitiveBinding { return v; } - @BindingMatch(type = { Expression.class }, - behavior = BindingBehavior.CONSUMES, - consumedCount = 1) + @BindingMatch(type = {Expression.class}, + behavior = BindingBehavior.CONSUMES, + consumedCount = 1) public Expression getExpression(ArgumentStack context) throws ParameterException, ExpressionException { String input = context.next(); try { @@ -222,15 +235,15 @@ public class FawePrimitiveBinding { /** * Gets a type from a {@link ArgumentStack}. * - * @param context the context + * @param context the context * @param modifiers a list of modifiers * @return the requested type * @throws ParameterException on error */ @BindingMatch(type = String.class, - behavior = BindingBehavior.CONSUMES, - consumedCount = 1, - provideModifiers = true) + behavior = BindingBehavior.CONSUMES, + consumedCount = 1, + provideModifiers = true) public String getString(ArgumentStack context, Annotation[] modifiers) throws ParameterException { String v = context.next(); @@ -246,8 +259,8 @@ public class FawePrimitiveBinding { * @throws ParameterException on error */ @BindingMatch(type = {Boolean.class, boolean.class}, - behavior = BindingBehavior.CONSUMES, - consumedCount = 1) + behavior = BindingBehavior.CONSUMES, + consumedCount = 1) public Boolean getBoolean(ArgumentStack context) throws ParameterException { return context.nextBoolean(); } @@ -260,9 +273,9 @@ public class FawePrimitiveBinding { * @throws ParameterException on error */ @BindingMatch(type = Vector3.class, - behavior = BindingBehavior.CONSUMES, - consumedCount = 1, - provideModifiers = true) + behavior = BindingBehavior.CONSUMES, + consumedCount = 1, + provideModifiers = true) public Vector3 getVector3(ArgumentStack context, Annotation[] modifiers) throws ParameterException { String radiusString = context.next(); String[] radii = radiusString.split(","); @@ -293,9 +306,9 @@ public class FawePrimitiveBinding { * @throws ParameterException on error */ @BindingMatch(type = Vector2.class, - behavior = BindingBehavior.CONSUMES, - consumedCount = 1, - provideModifiers = true) + behavior = BindingBehavior.CONSUMES, + consumedCount = 1, + provideModifiers = true) public Vector2 getVector2(ArgumentStack context, Annotation[] modifiers) throws ParameterException { String radiusString = context.next(); String[] radii = radiusString.split(","); @@ -314,69 +327,71 @@ public class FawePrimitiveBinding { throw new ParameterException("You must either specify 1 or 2 radius values."); } return Vector2.at(radiusX, radiusZ); - } /** + } + + /** * Gets a type from a {@link ArgumentStack}. - * - * @param context the context - * @return the requested type - * @throws ParameterException on error - */ - @BindingMatch(type = BlockVector3.class, - behavior = BindingBehavior.CONSUMES, - consumedCount = 1, - provideModifiers = true) - public BlockVector3 getBlockVector3(ArgumentStack context, Annotation[] modifiers) throws ParameterException { - String radiusString = context.next(); - String[] radii = radiusString.split(","); - final double radiusX, radiusY, radiusZ; - switch (radii.length) { - case 1: - radiusX = radiusY = radiusZ = Math.max(1, FawePrimitiveBinding.parseNumericInput(radii[0])); - break; + * + * @param context the context + * @return the requested type + * @throws ParameterException on error + */ + @BindingMatch(type = BlockVector3.class, + behavior = BindingBehavior.CONSUMES, + consumedCount = 1, + provideModifiers = true) + public BlockVector3 getBlockVector3(ArgumentStack context, Annotation[] modifiers) throws ParameterException { + String radiusString = context.next(); + String[] radii = radiusString.split(","); + final double radiusX, radiusY, radiusZ; + switch (radii.length) { + case 1: + radiusX = radiusY = radiusZ = Math.max(1, FawePrimitiveBinding.parseNumericInput(radii[0])); + break; - case 3: - radiusX = Math.max(1, FawePrimitiveBinding.parseNumericInput(radii[0])); - radiusY = Math.max(1, FawePrimitiveBinding.parseNumericInput(radii[1])); - radiusZ = Math.max(1, FawePrimitiveBinding.parseNumericInput(radii[2])); - break; + case 3: + radiusX = Math.max(1, FawePrimitiveBinding.parseNumericInput(radii[0])); + radiusY = Math.max(1, FawePrimitiveBinding.parseNumericInput(radii[1])); + radiusZ = Math.max(1, FawePrimitiveBinding.parseNumericInput(radii[2])); + break; - default: - throw new ParameterException("You must either specify 1 or 3 radius values."); - } - return BlockVector3.at(radiusX, radiusY, radiusZ); - } + default: + throw new ParameterException("You must either specify 1 or 3 radius values."); + } + return BlockVector3.at(radiusX, radiusY, radiusZ); + } - /** - * Gets a type from a {@link ArgumentStack}. - * - * @param context the context - * @return the requested type - * @throws ParameterException on error - */ - @BindingMatch(type = BlockVector2.class, - behavior = BindingBehavior.CONSUMES, - consumedCount = 1, - provideModifiers = true) - public BlockVector2 getBlockVector2(ArgumentStack context, Annotation[] modifiers) throws ParameterException { - String radiusString = context.next(); - String[] radii = radiusString.split(","); - final double radiusX, radiusZ; - switch (radii.length) { - case 1: - radiusX = radiusZ = Math.max(1, FawePrimitiveBinding.parseNumericInput(radii[0])); - break; + /** + * Gets a type from a {@link ArgumentStack}. + * + * @param context the context + * @return the requested type + * @throws ParameterException on error + */ + @BindingMatch(type = BlockVector2.class, + behavior = BindingBehavior.CONSUMES, + consumedCount = 1, + provideModifiers = true) + public BlockVector2 getBlockVector2(ArgumentStack context, Annotation[] modifiers) throws ParameterException { + String radiusString = context.next(); + String[] radii = radiusString.split(","); + final double radiusX, radiusZ; + switch (radii.length) { + case 1: + radiusX = radiusZ = Math.max(1, FawePrimitiveBinding.parseNumericInput(radii[0])); + break; - case 2: - radiusX = Math.max(1, FawePrimitiveBinding.parseNumericInput(radii[0])); - radiusZ = Math.max(1, FawePrimitiveBinding.parseNumericInput(radii[1])); - break; + case 2: + radiusX = Math.max(1, FawePrimitiveBinding.parseNumericInput(radii[0])); + radiusZ = Math.max(1, FawePrimitiveBinding.parseNumericInput(radii[1])); + break; - default: - throw new ParameterException("You must either specify 1 or 2 radius values."); - } - return BlockVector2.at(radiusX, radiusZ); - } + default: + throw new ParameterException("You must either specify 1 or 2 radius values."); + } + return BlockVector2.at(radiusX, radiusZ); + } /** * Try to parse numeric input as either a number or a mathematical expression. @@ -410,15 +425,15 @@ public class FawePrimitiveBinding { /** * Gets a type from a {@link ArgumentStack}. * - * @param context the context + * @param context the context * @param modifiers a list of modifiers * @return the requested type * @throws ParameterException on error */ @BindingMatch(type = {Integer.class, int.class}, - behavior = BindingBehavior.CONSUMES, - consumedCount = 1, - provideModifiers = true) + behavior = BindingBehavior.CONSUMES, + consumedCount = 1, + provideModifiers = true) public Integer getInteger(ArgumentStack context, Annotation[] modifiers) throws ParameterException { Double v = parseNumericInput(context.next()); if (v != null) { @@ -433,15 +448,15 @@ public class FawePrimitiveBinding { /** * Gets a type from a {@link ArgumentStack}. * - * @param context the context + * @param context the context * @param modifiers a list of modifiers * @return the requested type * @throws ParameterException on error */ @BindingMatch(type = {Short.class, short.class}, - behavior = BindingBehavior.CONSUMES, - consumedCount = 1, - provideModifiers = true) + behavior = BindingBehavior.CONSUMES, + consumedCount = 1, + provideModifiers = true) public Short getShort(ArgumentStack context, Annotation[] modifiers) throws ParameterException { Integer v = getInteger(context, modifiers); if (v != null) { @@ -453,15 +468,15 @@ public class FawePrimitiveBinding { /** * Gets a type from a {@link ArgumentStack}. * - * @param context the context + * @param context the context * @param modifiers a list of modifiers * @return the requested type * @throws ParameterException on error */ @BindingMatch(type = {Double.class, double.class}, - behavior = BindingBehavior.CONSUMES, - consumedCount = 1, - provideModifiers = true) + behavior = BindingBehavior.CONSUMES, + consumedCount = 1, + provideModifiers = true) public Double getDouble(ArgumentStack context, Annotation[] modifiers) throws ParameterException { Double v = parseNumericInput(context.next()); if (v != null) { @@ -475,15 +490,15 @@ public class FawePrimitiveBinding { /** * Gets a type from a {@link ArgumentStack}. * - * @param context the context + * @param context the context * @param modifiers a list of modifiers * @return the requested type * @throws ParameterException on error */ @BindingMatch(type = {Float.class, float.class}, - behavior = BindingBehavior.CONSUMES, - consumedCount = 1, - provideModifiers = true) + behavior = BindingBehavior.CONSUMES, + consumedCount = 1, + provideModifiers = true) public Float getFloat(ArgumentStack context, Annotation[] modifiers) throws ParameterException { Double v = getDouble(context, modifiers); if (v != null) { @@ -495,7 +510,7 @@ public class FawePrimitiveBinding { /** * Validate a number value using relevant modifiers. * - * @param number the number + * @param number the number * @param modifiers the list of modifiers to scan * @throws ParameterException on a validation error */ @@ -506,14 +521,10 @@ public class FawePrimitiveBinding { Range range = (Range) modifier; if (number < range.min()) { throw new ParameterException( - String.format( - "A valid value is greater than or equal to %s " + - "(you entered %s)", range.min(), number)); + String.format("A valid value is greater than or equal to %s (you entered %s)", range.min(), number)); } else if (number > range.max()) { throw new ParameterException( - String.format( - "A valid value is less than or equal to %s " + - "(you entered %s)", range.max(), number)); + String.format("A valid value is less than or equal to %s (you entered %s)", range.max(), number)); } } } @@ -522,7 +533,7 @@ public class FawePrimitiveBinding { /** * Validate a number value using relevant modifiers. * - * @param number the number + * @param number the number * @param modifiers the list of modifiers to scan * @throws ParameterException on a validation error */ @@ -534,13 +545,11 @@ public class FawePrimitiveBinding { if (number < range.min()) { throw new ParameterException( String.format( - "A valid value is greater than or equal to %s " + - "(you entered %s)", range.min(), number)); + "A valid value is greater than or equal to %s (you entered %s)", range.min(), number)); } else if (number > range.max()) { throw new ParameterException( String.format( - "A valid value is less than or equal to %s " + - "(you entered %s)", range.max(), number)); + "A valid value is less than or equal to %s (you entered %s)", range.max(), number)); } } } @@ -549,7 +558,7 @@ public class FawePrimitiveBinding { /** * Validate a string value using relevant modifiers. * - * @param string the string + * @param string the string * @param modifiers the list of modifiers to scan * @throws ParameterException on a validation error */ @@ -567,8 +576,7 @@ public class FawePrimitiveBinding { if (!string.matches(validate.regex())) { throw new ParameterException( String.format( - "The given text doesn't match the right " + - "format (technically speaking, the 'format' is %s)", + "The given text doesn't match the right format (technically speaking, the 'format' is %s)", validate.regex())); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/config/BBC.java b/worldedit-core/src/main/java/com/boydti/fawe/config/BBC.java index 72e1002be..41ab2f601 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/config/BBC.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/config/BBC.java @@ -434,7 +434,7 @@ public enum BBC { allNames.add(c.name()); allCats.add(c.category.toLowerCase()); } - final HashSet captions = new HashSet<>(); + final EnumSet captions = EnumSet.noneOf(BBC.class); boolean changed = false; for (final String key : keys) { final Object value = yml.get(key); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/config/Settings.java b/worldedit-core/src/main/java/com/boydti/fawe/config/Settings.java index 1d0e4c183..5e234d644 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/config/Settings.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/config/Settings.java @@ -29,7 +29,7 @@ public class Settings extends Config { @Comment({"Options: cn, de, es, fr, it, nl, ru, tr", "Create a PR to contribute a translation: https://github.com/IntellectualSites/FastAsyncWorldEdit-1.13/tree/master/worldedit-core/src/main/resources",}) public String LANGUAGE = ""; - @Comment("Send anonymous usage statistics") + @Comment("@deprecated - use bstats config.yml") public boolean METRICS = true; @Comment({ "Set true to enable WorldEdit restrictions per region (e.g. PlotSquared or WorldGuard).", @@ -257,8 +257,8 @@ public class Settings extends Config { public static class QUEUE { @Comment({ "This should equal the number of processors you have", - " - Set this to 1 if you need reliable `/timings`" }) + @Final public int PARALLEL_THREADS = Math.max(1, Runtime.getRuntime().availableProcessors()); @Create public static PROGRESS PROGRESS; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/example/DefaultFaweQueueMap.java b/worldedit-core/src/main/java/com/boydti/fawe/example/DefaultFaweQueueMap.java deleted file mode 100644 index 08cb86e52..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/example/DefaultFaweQueueMap.java +++ /dev/null @@ -1,195 +0,0 @@ -package com.boydti.fawe.example; - -import com.boydti.fawe.object.FaweChunk; -import com.boydti.fawe.object.FaweQueue; -import com.boydti.fawe.object.RunnableVal; -import com.boydti.fawe.util.MathMan; -import com.boydti.fawe.util.SetQueue; -import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.concurrent.ExecutorCompletionService; -import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -public class DefaultFaweQueueMap implements IFaweQueueMap { - - private final MappedFaweQueue parent; - - public DefaultFaweQueueMap(MappedFaweQueue parent) { - this.parent = parent; - } - - public final Long2ObjectOpenHashMap blocks = new Long2ObjectOpenHashMap() { - @Override - public FaweChunk put(Long key, FaweChunk value) { - return put((long) key, value); - } - - @Override - public FaweChunk put(long key, FaweChunk value) { - if (parent.getProgressTask() != null) { - try { - parent.getProgressTask().run(FaweQueue.ProgressType.QUEUE, size() + 1); - } catch (Throwable e) { - e.printStackTrace(); - } - } - synchronized (this) { - return super.put(key, value); - } - } - }; - - @Override - public Collection getFaweChunks() { - synchronized (blocks) { - return new HashSet<>(blocks.values()); - } - } - - @Override - public void forEachChunk(RunnableVal onEach) { - synchronized (blocks) { - for (Map.Entry entry : blocks.entrySet()) { - onEach.run(entry.getValue()); - } - } - } - - @Override - public FaweChunk getFaweChunk(int cx, int cz) { - if (cx == lastX && cz == lastZ) { - return lastWrappedChunk; - } - long pair = MathMan.pairInt(cx, cz); - FaweChunk chunk = this.blocks.get(pair); - if (chunk == null) { - chunk = this.getNewFaweChunk(cx, cz); - FaweChunk previous = this.blocks.put(pair, chunk); - if (previous != null) { - blocks.put(pair, previous); - return previous; - } - this.blocks.put(pair, chunk); - } - return chunk; - } - - @Override - public FaweChunk getCachedFaweChunk(int cx, int cz) { - if (cx == lastX && cz == lastZ) { - return lastWrappedChunk; - } - long pair = MathMan.pairInt(cx, cz); - FaweChunk chunk = this.blocks.get(pair); - lastWrappedChunk = chunk; - return chunk; - } - - @Override - public void add(FaweChunk chunk) { - long pair = MathMan.pairInt(chunk.getX(), chunk.getZ()); - FaweChunk previous = this.blocks.put(pair, chunk); - if (previous != null) { - blocks.put(pair, previous); - } - } - - - @Override - public void clear() { - blocks.clear(); - } - - @Override - public int size() { - return blocks.size(); - } - - private FaweChunk getNewFaweChunk(int cx, int cz) { - return parent.getFaweChunk(cx, cz); - } - - private volatile FaweChunk lastWrappedChunk; - private int lastX = Integer.MIN_VALUE; - private int lastZ = Integer.MIN_VALUE; - - @Override - public boolean next(int amount, long time) { - synchronized (blocks) { - try { - boolean skip = parent.getStage() == SetQueue.QueueStage.INACTIVE; - int added = 0; - Iterator> iter = blocks.entrySet().iterator(); - if (amount == 1) { - long start = System.currentTimeMillis(); - do { - if (iter.hasNext()) { - FaweChunk chunk = iter.next().getValue(); - if (skip && chunk == lastWrappedChunk) { - continue; - } - iter.remove(); - parent.start(chunk); - chunk.call(); - parent.end(chunk); - } else { - break; - } - } while (System.currentTimeMillis() - start < time); - } else { - ExecutorCompletionService service = SetQueue.IMP.getCompleterService(); - ForkJoinPool pool = SetQueue.IMP.getForkJoinPool(); - boolean result = true; - // amount = 8; - for (int i = 0; i < amount && (result = iter.hasNext()); i++) { - Map.Entry item = iter.next(); - FaweChunk chunk = item.getValue(); - if (skip && chunk == lastWrappedChunk) { - i--; - continue; - } - iter.remove(); - parent.start(chunk); - service.submit(chunk); - added++; - } - // if result, then submitted = amount - if (result) { - long start = System.currentTimeMillis(); - while (System.currentTimeMillis() - start < time && result) { - if (result = iter.hasNext()) { - Map.Entry item = iter.next(); - FaweChunk chunk = item.getValue(); - if (skip && chunk == lastWrappedChunk) { - continue; - } - iter.remove(); - parent.start(chunk); - service.submit(chunk); - Future future = service.poll(50, TimeUnit.MILLISECONDS); - if (future != null) { - FaweChunk fc = (FaweChunk) future.get(); - parent.end(fc); - } - } - } - } - pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS); - Future future; - while ((future = service.poll()) != null) { - FaweChunk fc = (FaweChunk) future.get(); - parent.end(fc); - } - } - } catch (Throwable e) { - e.printStackTrace(); - } - return !blocks.isEmpty(); - } - } -} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/example/IFaweQueueMap.java b/worldedit-core/src/main/java/com/boydti/fawe/example/IFaweQueueMap.java deleted file mode 100644 index 2f2bbaa38..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/example/IFaweQueueMap.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.boydti.fawe.example; - -import com.boydti.fawe.object.FaweChunk; -import com.boydti.fawe.object.RunnableVal; -import java.util.Collection; - -public interface IFaweQueueMap { - - Collection getFaweChunks(); - - void forEachChunk(RunnableVal onEach); - - FaweChunk getFaweChunk(int cx, int cz); - - FaweChunk getCachedFaweChunk(int cx, int cz); - - void add(FaweChunk chunk); - - void clear(); - - int size(); - - boolean next(int size, long time); -} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/example/IntFaweChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/example/IntFaweChunk.java deleted file mode 100644 index 9774c4786..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/example/IntFaweChunk.java +++ /dev/null @@ -1,244 +0,0 @@ -package com.boydti.fawe.example; - -import com.boydti.fawe.object.FaweChunk; -import com.boydti.fawe.object.FaweQueue; -import com.boydti.fawe.util.MathMan; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BlockID; - -import java.util.*; - -public abstract class IntFaweChunk extends FaweChunk { - - public final int[][] setBlocks; - public final short[] count; - public final short[] air; - - public BiomeType[] biomes; - public HashMap tiles; - public HashSet entities; - public HashSet entityRemoves; - - public T chunk; - - public IntFaweChunk(FaweQueue parent, int x, int z, int[][] setBlocks, short[] count, short[] air) { - super(parent, x, z); - this.setBlocks = setBlocks; - this.count = count; - this.air = air; - } - - /** - * A FaweSections object represents a chunk and the blocks that you wish to change in it. - * - * @param parent - * @param x - * @param z - */ - public IntFaweChunk(FaweQueue parent, int x, int z) { - super(parent, x, z); - this.setBlocks = new int[HEIGHT >> 4][]; - this.count = new short[HEIGHT >> 4]; - this.air = new short[HEIGHT >> 4]; - } - - @Override - public V getParent() { - return (V) super.getParent(); - } - - @Override - public T getChunk() { - if (this.chunk == null) { - this.chunk = getNewChunk(); - } - return this.chunk; - } - - public abstract T getNewChunk(); - - @Override - public void setLoc(final FaweQueue parent, int x, int z) { - super.setLoc(parent, x, z); - this.chunk = null; - } - - /** - * Get the number of block changes in a specified section - * - * @param i - * @return - */ - public int getCount(final int i) { - return this.count[i]; - } - - public int getAir(final int i) { - return this.air[i]; - } - - public void setCount(final int i, final short value) { - this.count[i] = value; - } - - public int getTotalCount() { - int total = 0; - for (short value : count) { - total += Math.min(4096, value); - } - return total; - } - - public int getTotalAir() { - int total = 0; - for (short value : air) { - total += Math.min(4096, value); - } - return total; - } - - @Override - public int getBitMask() { - int bitMask = 0; - for (int section = 0; section < setBlocks.length; section++) { - if (setBlocks[section] != null) { - bitMask += 1 << section; - } - } - return bitMask; - } - - /** - * Get the raw data for a section - * - * @param i - * @return - */ - @Override - public int[] getIdArray(final int i) { - return this.setBlocks[i]; - } - - @Override - public int[][] getCombinedIdArrays() { - return this.setBlocks; - } - - @Override - public BiomeType[] getBiomeArray() { - return this.biomes; - } - - @Override - public int getBlockCombinedId(int x, int y, int z) { - int[] array = getIdArray(y >> 4); - if (array == null) { - return 0; - } - return array[(((y & 0xF) << 8) | (z << 4) | x)]; - } - - @Override - public void setTile(int x, int y, int z, CompoundTag tile) { - if (tiles == null) { - tiles = new HashMap<>(); - } - short pair = MathMan.tripleBlockCoord(x, y, z); - tiles.put(pair, tile); - } - - @Override - public CompoundTag getTile(int x, int y, int z) { - if (tiles == null) { - return null; - } - short pair = MathMan.tripleBlockCoord(x, y, z); - return tiles.get(pair); - } - - @Override - public Map getTiles() { - return tiles == null ? new HashMap<>() : tiles; - } - - @Override - public Set getEntities() { - return entities == null ? Collections.emptySet() : entities; - } - - @Override - public void setEntity(CompoundTag tag) { - if (entities == null) { - entities = new HashSet<>(); - } - entities.add(tag); - } - - @Override - public void removeEntity(UUID uuid) { - if (entityRemoves == null) { - entityRemoves = new HashSet<>(); - } - entityRemoves.add(uuid); - } - - @Override - public HashSet getEntityRemoves() { - return entityRemoves == null ? new HashSet<>() : entityRemoves; - } - - @Override - public void setBlock(int x, int y, int z, int combinedId) { - final int i = y >> 4; - int[] vs = this.setBlocks[i]; - if (vs == null) { - vs = this.setBlocks[i] = new int[4096]; - } - int index = (((y & 15) << 8) | (z << 4) | x); - int existing = vs[index]; - vs[index] = combinedId; - switch (existing) { - case 0: - this.count[i]++; - switch (combinedId) { - case 0: - case BlockID.AIR: - case BlockID.CAVE_AIR: - case BlockID.VOID_AIR: - this.air[i]++; - } - break; - case BlockID.AIR: - case BlockID.CAVE_AIR: - case BlockID.VOID_AIR: - switch (combinedId) { - case 0: - case BlockID.AIR: - case BlockID.CAVE_AIR: - case BlockID.VOID_AIR: - break; - default: - this.air[i]--; - - } - } - return; - } - - @Deprecated - public void setBitMask(int ignore) { - // Remove - } - - @Override - public void setBiome(final int x, final int z, BiomeType biome) { - if (this.biomes == null) { - this.biomes = new BiomeType[256]; - } - biomes[((z & 15) << 4) + (x & 15)] = biome; - } - - @Override - public abstract IntFaweChunk copy(boolean shallow); -} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java b/worldedit-core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java deleted file mode 100644 index aa04b611f..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java +++ /dev/null @@ -1,216 +0,0 @@ -package com.boydti.fawe.example; - -import com.boydti.fawe.object.FaweChunk; -import com.boydti.fawe.util.TaskManager; -import com.sk89q.worldedit.world.World; -import com.sk89q.worldedit.world.block.BlockTypes; - -public abstract class NMSMappedFaweQueue extends MappedFaweQueue { - - private final int maxY; - - public NMSMappedFaweQueue(World world) { - super(world); - this.maxY = world.getMaxY(); - } - - public NMSMappedFaweQueue(String world) { - super(world); - this.maxY = 256; - } - - public NMSMappedFaweQueue(String world, IFaweQueueMap map) { - super(world, map); - this.maxY = 256; - } - - public NMSMappedFaweQueue(World world, IFaweQueueMap map) { - super(world, map); - this.maxY = world.getMaxY(); - } - - @Override - public void runTasks() { - super.runTasks(); - if (!getRelighter().isEmpty()) { - TaskManager.IMP.async(() -> { - if (getSettings().IMP.LIGHTING.REMOVE_FIRST) { - getRelighter().removeAndRelight(hasSky()); - } else { - getRelighter().fixLightingSafe(hasSky()); - } - }); - } - } - - private final Relighter relighter = getSettings().IMP.LIGHTING.MODE > 0 ? new NMSRelighter(this) : NullRelighter.INSTANCE; - - @Override - public Relighter getRelighter() { - return relighter; - } - - @Override - public void end(FaweChunk chunk) { - super.end(chunk); - if (getSettings().IMP.LIGHTING.MODE == 0) { - sendChunk(chunk); - return; - } - if (!getSettings().IMP.LIGHTING.DELAY_PACKET_SENDING) { - sendChunk(chunk); - } - if (getSettings().IMP.LIGHTING.MODE == 2) { - getRelighter().addChunk(chunk.getX(), chunk.getZ(), null, chunk.getBitMask()); - return; - } - IntFaweChunk cfc = (IntFaweChunk) chunk; - boolean relight = false; - byte[] fix = new byte[(maxY + 1) >> 4]; - boolean sky = hasSky(); - if (sky) { - int layers = FaweChunk.HEIGHT >> 4; - for (int i = layers - 1; i >= 0; i--) { - int air = cfc.getAir(i); - int solid = cfc.getCount(i); - if (air == 4096) { - fix[i] = Relighter.SkipReason.AIR; - } else if (air == 0 && solid == 4096) { - fix[i] = Relighter.SkipReason.SOLID; - } else if (solid == 0 && relight == false) { - fix[i] = Relighter.SkipReason.AIR; - } else { - fix[i] = Relighter.SkipReason.NONE; - relight = true; - } - } - } - if (relight) { - getRelighter().addChunk(chunk.getX(), chunk.getZ(), fix, chunk.getBitMask()); - } else if (getSettings().IMP.LIGHTING.DELAY_PACKET_SENDING) { - sendChunk(chunk); - } - } - - @Override - public void sendChunk(final FaweChunk fc) { - try { - refreshChunk(fc); - } catch (Throwable e) { - e.printStackTrace(); - } - } - - public abstract void setFullbright(CHUNKSECTION sections); - - public boolean removeLighting(CHUNKSECTION sections, RelightMode mode, boolean hasSky) { - boolean result = false; - for (int i = 0; i < 16; i++) { - SECTION section = getCachedSection(sections, i); - if (section != null) { - result |= removeSectionLighting(section, i, hasSky); - } - } - return result; - } - - public abstract boolean removeSectionLighting(SECTION sections, int layer, boolean hasSky); - - public boolean isSurrounded(final char[][] sections, final int x, final int y, final int z) { - return this.isSolid(this.getId(sections, x, y + 1, z)) - && this.isSolid(this.getId(sections, x + 1, y - 1, z)) - && this.isSolid(this.getId(sections, x - 1, y, z)) - && this.isSolid(this.getId(sections, x, y, z + 1)) - && this.isSolid(this.getId(sections, x, y, z - 1)); - } - - public boolean isSolid(final int id) { - return !BlockTypes.get(id).getMaterial().isTranslucent(); - } - - public int getId(final char[][] sections, final int x, final int y, final int z) { - if ((x < 0) || (x > 15) || (z < 0) || (z > 15)) { - return BlockTypes.AIR.getInternalId(); - } - if ((y < 0) || (y > maxY)) { - return BlockTypes.AIR.getInternalId(); - } - final int i = y >> 4; - final char[] section = sections[i]; - if (section == null) { - return 0; - } - return section[(((y & 0xF) << 8) | (z << 4) | x)] >> 4; - } - - public void saveChunk(CHUNK chunk) { - } - - public abstract void relight(int x, int y, int z); - - public abstract void relightBlock(int x, int y, int z); - - public abstract void relightSky(int x, int y, int z); - - public void setSkyLight(int x, int y, int z, int value) { - int cx = x >> 4; - int cz = z >> 4; - int cy = y >> 4; - if (cx != lastSectionX || cz != lastSectionZ) { - lastSectionX = cx; - lastSectionZ = cz; - lastChunk = ensureChunkLoaded(cx, cz); - if (lastChunk != null) { - lastChunkSections = getSections(lastChunk); - lastSection = getCachedSection(lastChunkSections, cy); - } else { - lastChunkSections = null; - return; - } - } else if (cy != lastSectionY) { - if (lastChunkSections != null) { - lastSection = getCachedSection(lastChunkSections, cy); - } else { - return; - } - } - if (lastSection == null) { - return; - } - setSkyLight(lastSection, x, y, z, value); - } - - public void setBlockLight(int x, int y, int z, int value) { - int cx = x >> 4; - int cz = z >> 4; - int cy = y >> 4; - if (cx != lastSectionX || cz != lastSectionZ) { - lastSectionX = cx; - lastSectionZ = cz; - lastChunk = ensureChunkLoaded(cx, cz); - if (lastChunk != null) { - lastChunkSections = getSections(lastChunk); - lastSection = getCachedSection(lastChunkSections, cy); - } else { - lastChunkSections = null; - return; - } - } else if (cy != lastSectionY) { - if (lastChunkSections != null) { - lastSection = getCachedSection(lastChunkSections, cy); - } else { - return; - } - } - if (lastSection == null) { - return; - } - setBlockLight(lastSection, x, y, z, value); - } - - public abstract void setSkyLight(SECTION section, int x, int y, int z, int value); - - public abstract void setBlockLight(SECTION section, int x, int y, int z, int value); - - public abstract void refreshChunk(FaweChunk fs); -} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/example/NMSRelighter.java b/worldedit-core/src/main/java/com/boydti/fawe/example/NMSRelighter.java deleted file mode 100644 index ed33a9b5e..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/example/NMSRelighter.java +++ /dev/null @@ -1,597 +0,0 @@ -package com.boydti.fawe.example; - -import com.boydti.fawe.FaweCache; -import com.boydti.fawe.config.Settings; -import com.boydti.fawe.object.FaweChunk; -import com.boydti.fawe.object.FaweQueue; -import com.boydti.fawe.object.IntegerTrio; -import com.boydti.fawe.object.RunnableVal; -import com.boydti.fawe.object.collection.BlockVectorSet; -import com.boydti.fawe.util.MathMan; -import com.boydti.fawe.util.TaskManager; -import com.google.common.io.LineReader; -import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; - -import java.io.*; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Queue; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicBoolean; - -public class NMSRelighter implements Relighter { - private final NMSMappedFaweQueue queue; - - private final Map skyToRelight; - private final Object present = new Object(); - private final Map chunksToSend; - private final ConcurrentLinkedQueue queuedSkyToRelight = new ConcurrentLinkedQueue<>(); - - private final Map lightQueue; - private final AtomicBoolean lightLock = new AtomicBoolean(false); - private final ConcurrentHashMap concurrentLightQueue; - - private final int maxY; - private volatile boolean relighting = false; - - public final IntegerTrio mutableBlockPos = new IntegerTrio(); - - private static final int DISPATCH_SIZE = 64; - private boolean removeFirst; - - public NMSRelighter(NMSMappedFaweQueue queue) { - this.queue = queue; - this.skyToRelight = new Long2ObjectOpenHashMap<>(); - this.lightQueue = new Long2ObjectOpenHashMap<>(); - this.chunksToSend = new Long2ObjectOpenHashMap<>(); - this.concurrentLightQueue = new ConcurrentHashMap<>(); - this.maxY = queue.getMaxY(); - } - - @Override - public boolean isEmpty() { - return skyToRelight.isEmpty() && lightQueue.isEmpty() && queuedSkyToRelight.isEmpty() && concurrentLightQueue.isEmpty(); - } - - @Override - public synchronized void removeAndRelight(boolean sky) { - removeFirst = true; - fixLightingSafe(sky); - removeFirst = false; - } - - private void set(int x, int y, int z, long[][][] map) { - long[][] m1 = map[z]; - if (m1 == null) { - m1 = map[z] = new long[16][]; - } - long[] m2 = m1[x]; - if (m2 == null) { - m2 = m1[x] = new long[4]; - } - long value = m2[y >> 6] |= 1l << y; - } - - public void addLightUpdate(int x, int y, int z) { - long index = MathMan.pairInt(x >> 4, z >> 4); - if (lightLock.compareAndSet(false, true)) { - synchronized (lightQueue) { - try { - long[][][] currentMap = lightQueue.get(index); - if (currentMap == null) { - currentMap = new long[16][][]; - this.lightQueue.put(index, currentMap); - } - set(x & 15, y, z & 15, currentMap); - } finally { - lightLock.set(false); - } - } - } else { - long[][][] currentMap = concurrentLightQueue.get(index); - if (currentMap == null) { - currentMap = new long[16][][]; - this.concurrentLightQueue.put(index, currentMap); - } - set(x & 15, y, z & 15, currentMap); - } - } - - public synchronized void clear() { - queuedSkyToRelight.clear(); - skyToRelight.clear(); - chunksToSend.clear(); - lightQueue.clear(); - concurrentLightQueue.clear(); - } - - public boolean addChunk(int cx, int cz, byte[] fix, int bitmask) { - RelightSkyEntry toPut = new RelightSkyEntry(cx, cz, fix, bitmask); - queuedSkyToRelight.add(toPut); - return true; - } - - private synchronized Map getSkyMap() { - RelightSkyEntry entry; - while ((entry = queuedSkyToRelight.poll()) != null) { - long pair = MathMan.pairInt(entry.x, entry.z); - RelightSkyEntry existing = skyToRelight.put(pair, entry); - if (existing != null) { - entry.bitmask |= existing.bitmask; - if (entry.fix != null) { - for (int i = 0; i < entry.fix.length; i++) { - entry.fix[i] &= existing.fix[i]; - } - } - } - } - return skyToRelight; - } - - public synchronized void removeLighting() { - Iterator> iter = getSkyMap().entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry entry = iter.next(); - RelightSkyEntry chunk = entry.getValue(); - long pair = entry.getKey(); - Integer existing = chunksToSend.get(pair); - chunksToSend.put(pair, chunk.bitmask | (existing != null ? existing : 0)); - queue.ensureChunkLoaded(chunk.x, chunk.z); - Object sections = queue.getCachedSections(queue.getWorld(), chunk.x, chunk.z); - queue.removeLighting(sections, FaweQueue.RelightMode.ALL, queue.hasSky()); - iter.remove(); - } - } - - public void updateBlockLight(Map map) { - int size = map.size(); - if (size == 0) { - return; - } - Queue lightPropagationQueue = new ArrayDeque<>(); - Queue lightRemovalQueue = new ArrayDeque<>(); - Map visited = new HashMap<>(); - Map removalVisited = new HashMap<>(); - - Iterator> iter = map.entrySet().iterator(); - while (iter.hasNext() && size-- > 0) { - Map.Entry entry = iter.next(); - long index = entry.getKey(); - long[][][] blocks = entry.getValue(); - int chunkX = MathMan.unpairIntX(index); - int chunkZ = MathMan.unpairIntY(index); - int bx = chunkX << 4; - int bz = chunkZ << 4; - for (int lz = 0; lz < blocks.length; lz++) { - long[][] m1 = blocks[lz]; - if (m1 == null) continue; - for (int lx = 0; lx < m1.length; lx++) { - long[] m2 = m1[lx]; - if (m2 == null) continue; - for (int i = 0; i < m2.length; i++) { - int yStart = i << 6; - long value = m2[i]; - if (value != 0) { - for (int j = 0; j < 64; j++) { - if (((value >> j) & 1) == 1) { - int x = lx + bx; - int y = yStart + j; - int z = lz + bz; - int oldLevel = queue.getEmmittedLight(x, y, z); - int newLevel = queue.getBrightness(x, y, z); - if (oldLevel != newLevel) { - queue.setBlockLight(x, y, z, newLevel); - IntegerTrio node = new IntegerTrio(x, y, z); - if (newLevel < oldLevel) { - removalVisited.put(node, present); - lightRemovalQueue.add(new Object[]{node, oldLevel}); - } else { - visited.put(node, present); - lightPropagationQueue.add(node); - } - } - } - } - } - } - } - } - iter.remove(); - } - - while (!lightRemovalQueue.isEmpty()) { - Object[] val = lightRemovalQueue.poll(); - IntegerTrio node = (IntegerTrio) val[0]; - int lightLevel = (int) val[1]; - - this.computeRemoveBlockLight(node.x - 1, node.y, node.z, lightLevel, lightRemovalQueue, lightPropagationQueue, removalVisited, visited); - this.computeRemoveBlockLight(node.x + 1, node.y, node.z, lightLevel, lightRemovalQueue, lightPropagationQueue, removalVisited, visited); - if (node.y > 0) { - this.computeRemoveBlockLight(node.x, node.y - 1, node.z, lightLevel, lightRemovalQueue, lightPropagationQueue, removalVisited, visited); - } - if (node.y < 255) { - this.computeRemoveBlockLight(node.x, node.y + 1, node.z, lightLevel, lightRemovalQueue, lightPropagationQueue, removalVisited, visited); - } - this.computeRemoveBlockLight(node.x, node.y, node.z - 1, lightLevel, lightRemovalQueue, lightPropagationQueue, removalVisited, visited); - this.computeRemoveBlockLight(node.x, node.y, node.z + 1, lightLevel, lightRemovalQueue, lightPropagationQueue, removalVisited, visited); - } - - while (!lightPropagationQueue.isEmpty()) { - IntegerTrio node = lightPropagationQueue.poll(); - int lightLevel = queue.getEmmittedLight(node.x, node.y, node.z); - if (lightLevel > 1) { - this.computeSpreadBlockLight(node.x - 1, node.y, node.z, lightLevel, lightPropagationQueue, visited); - this.computeSpreadBlockLight(node.x + 1, node.y, node.z, lightLevel, lightPropagationQueue, visited); - if (node.y > 0) { - this.computeSpreadBlockLight(node.x, node.y - 1, node.z, lightLevel, lightPropagationQueue, visited); - } - if (node.y < 255) { - this.computeSpreadBlockLight(node.x, node.y + 1, node.z, lightLevel, lightPropagationQueue, visited); - } - this.computeSpreadBlockLight(node.x, node.y, node.z - 1, lightLevel, lightPropagationQueue, visited); - this.computeSpreadBlockLight(node.x, node.y, node.z + 1, lightLevel, lightPropagationQueue, visited); - } - } - } - - private void computeRemoveBlockLight(int x, int y, int z, int currentLight, Queue queue, Queue spreadQueue, Map visited, - Map spreadVisited) { - int current = this.queue.getEmmittedLight(x, y, z); - if (current != 0 && current < currentLight) { - this.queue.setBlockLight(x, y, z, 0); - if (current > 1) { - if (!visited.containsKey(mutableBlockPos)) { - IntegerTrio index = new IntegerTrio(x, y, z); - visited.put(index, present); - queue.add(new Object[]{index, current}); - } - } - } else if (current >= currentLight) { - mutableBlockPos.set(x, y, z); - if (!spreadVisited.containsKey(mutableBlockPos)) { - IntegerTrio index = new IntegerTrio(x, y, z); - spreadVisited.put(index, present); - spreadQueue.add(index); - } - } - } - - private void computeSpreadBlockLight(int x, int y, int z, int currentLight, Queue queue, Map visited) { - currentLight = currentLight - Math.max(1, this.queue.getOpacity(x, y, z)); - if (currentLight > 0) { - int current = this.queue.getEmmittedLight(x, y, z); - if (current < currentLight) { - this.queue.setBlockLight(x, y, z, currentLight); - mutableBlockPos.set(x, y, z); - if (!visited.containsKey(mutableBlockPos)) { - visited.put(new IntegerTrio(x, y, z), present); - if (currentLight > 1) { - queue.add(new IntegerTrio(x, y, z)); - } - } - } - } - } - - public void fixLightingSafe(boolean sky) { - if (isEmpty()) return; - try { - if (sky) { - fixSkyLighting(); - } else { - synchronized (this) { - Map map = getSkyMap(); - Iterator> iter = map.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry entry = iter.next(); - chunksToSend.put(entry.getKey(), entry.getValue().bitmask); - iter.remove(); - } - } - } - fixBlockLighting(); - sendChunks(); - } catch (Throwable e) { - e.printStackTrace(); - } - } - - public void fixBlockLighting() { - synchronized (lightQueue) { - while (!lightLock.compareAndSet(false, true)); - try { - updateBlockLight(this.lightQueue); - } finally { - lightLock.set(false); - } - } - } - - public synchronized void sendChunks() { - RunnableVal runnable = new RunnableVal() { - @Override - public void run(Object value) { - Iterator> iter = chunksToSend.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry entry = iter.next(); - long pair = entry.getKey(); - int bitMask = entry.getValue(); - int x = MathMan.unpairIntX(pair); - int z = MathMan.unpairIntY(pair); - queue.sendChunk(x, z, bitMask); - iter.remove(); - } - } - }; - if (Settings.IMP.LIGHTING.ASYNC) { - runnable.run(); - } else { - TaskManager.IMP.sync(runnable); - } - } - - private boolean isTransparent(int x, int y, int z) { - return queue.getOpacity(x, y, z) < 15; - } - - public synchronized void fixSkyLighting() { - // Order chunks - Map map = getSkyMap(); - ArrayList chunksList = new ArrayList<>(map.size()); - Iterator> iter = map.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry entry = iter.next(); - chunksToSend.put(entry.getKey(), entry.getValue().bitmask); - chunksList.add(entry.getValue()); - iter.remove(); - } - Collections.sort(chunksList); - int size = chunksList.size(); - if (size > DISPATCH_SIZE) { - int amount = (size + DISPATCH_SIZE - 1) / DISPATCH_SIZE; - for (int i = 0; i < amount; i++) { - int start = i * DISPATCH_SIZE; - int end = Math.min(size, start + DISPATCH_SIZE); - List sub = chunksList.subList(start, end); - fixSkyLighting(sub); - } - } else { - fixSkyLighting(chunksList); - } - } - - public void fill(byte[] mask, int chunkX, int y, int chunkZ, byte reason) { - if (y >= FaweChunk.HEIGHT) { - Arrays.fill(mask, (byte) 15); - return; - } - switch (reason) { - case SkipReason.SOLID: { - Arrays.fill(mask, (byte) 0); - return; - } - case SkipReason.AIR: { - int bx = chunkX << 4; - int bz = chunkZ << 4; - int index = 0; - for (int z = 0; z < 16; z++) { - for (int x = 0; x < 16; x++) { - mask[index++] = (byte) queue.getSkyLight(bx + x, y, bz + z); - } - } - } - } - } - - private void fixSkyLighting(List sorted) { - RelightSkyEntry[] chunks = sorted.toArray(new RelightSkyEntry[sorted.size()]); - boolean remove = this.removeFirst; - BlockVectorSet chunkSet = null; - if (remove) { - chunkSet = new BlockVectorSet(); - BlockVectorSet tmpSet = new BlockVectorSet(); - for (RelightSkyEntry chunk : chunks) { - tmpSet.add(chunk.x, 0, chunk.z); - } - for (RelightSkyEntry chunk : chunks) { - int x = chunk.x; - int z = chunk.z; - if (tmpSet.contains(x + 1, 0, z) && tmpSet.contains(x - 1, 0, z) && tmpSet.contains(x, 0, z + 1) && tmpSet.contains(x, 0, z - 1)) { - chunkSet.add(x, 0, z); - } - } - } - -// byte[] cacheX = FaweCache.CACHE_X[0]; -// byte[] cacheZ = FaweCache.CACHE_Z[0]; - for (int y = FaweChunk.HEIGHT - 1; y > 0; y--) { - for (RelightSkyEntry chunk : chunks) { // Propogate skylight - int layer = y >> 4; - byte[] mask = chunk.mask; - if (chunk.fix[layer] != SkipReason.NONE) { - if ((y & 15) == 0 && layer != 0 && chunk.fix[layer - 1] == SkipReason.NONE) { - fill(mask, chunk.x, y, chunk.z, chunk.fix[layer]); - } - continue; - } - int bx = chunk.x << 4; - int bz = chunk.z << 4; - Object chunkObj = queue.ensureChunkLoaded(chunk.x, chunk.z); - Object sections = queue.getCachedSections(queue.getWorld(), chunk.x, chunk.z); - if (sections == null) continue; - Object section = queue.getCachedSection(sections, layer); - if (section == null) continue; - chunk.smooth = false; - - if (remove && (y & 15) == 15 && chunkSet.contains(chunk.x, 0, chunk.z)) { - queue.removeSectionLighting(section, y >> 4, true); - } - - for (int z = 0, j = 0; z < 16; z++) { - for (int x = 0; x < 16; x++, j++) { - byte value = mask[j]; - byte pair = (byte) queue.getOpacityBrightnessPair(section, x, y, z); - int opacity = MathMan.unpair16x(pair); - int brightness = MathMan.unpair16y(pair); - if (brightness > 1 && (brightness != 15 || opacity != 15)) { - addLightUpdate(bx + x, y, bz + z); - } - switch (value) { - case 0: - if (opacity > 1) { - queue.setSkyLight(section, x, y, z, 0); - continue; - } - break; - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: - case 14: - if (opacity >= value) { - mask[j] = 0; - queue.setSkyLight(section, x, y, z, 0); - continue; - } - if (opacity <= 1) { - mask[j] = --value; - } else { - mask[j] = value = (byte) Math.max(0, value - opacity); - } - break; - case 15: - if (opacity > 1) { - value -= opacity; - mask[j] = value; - } - queue.setSkyLight(section, x, y, z, value); - continue; - } - chunk.smooth = true; - queue.setSkyLight(section, x, y, z, value); - } - } - queue.saveChunk(chunkObj); - } - for (RelightSkyEntry chunk : chunks) { // Smooth forwards - if (chunk.smooth) { - smoothSkyLight(chunk, y, true); - } - } - for (int i = chunks.length - 1; i >= 0; i--) { // Smooth backwards - RelightSkyEntry chunk = chunks[i]; - if (chunk.smooth) { - smoothSkyLight(chunk, y, false); - } - } - } - } - - public void smoothSkyLight(RelightSkyEntry chunk, int y, boolean direction) { - byte[] mask = chunk.mask; - int bx = chunk.x << 4; - int bz = chunk.z << 4; - queue.ensureChunkLoaded(chunk.x, chunk.z); - Object sections = queue.getCachedSections(queue.getWorld(), chunk.x, chunk.z); - if (sections == null) return; - Object section = queue.getCachedSection(sections, y >> 4); - if (section == null) return; - if (direction) { - for (int j = 0; j < 256; j++) { - int x = j & 15; - int z = j >> 4; - if (mask[j] >= 14 || (mask[j] == 0 && queue.getOpacity(section, x, y, z) > 1)) { - continue; - } - byte value = mask[j]; - if ((value = (byte) Math.max(queue.getSkyLight(bx + x - 1, y, bz + z) - 1, value)) >= 14) ; - else if ((value = (byte) Math.max(queue.getSkyLight(bx + x, y, bz + z - 1) - 1, value)) >= 14) ; - if (value > mask[j]) queue.setSkyLight(section, x, y, z, mask[j] = value); - } - } else { - for (int j = 255; j >= 0; j--) { - int x = j & 15; - int z = j >> 4; - if (mask[j] >= 14 || (mask[j] == 0 && queue.getOpacity(section, x, y, z) > 1)) { - continue; - } - byte value = mask[j]; - if ((value = (byte) Math.max(queue.getSkyLight(bx + x + 1, y, bz + z) - 1, value)) >= 14) ; - else if ((value = (byte) Math.max(queue.getSkyLight(bx + x, y, bz + z + 1) - 1, value)) >= 14) ; - if (value > mask[j]) queue.setSkyLight(section, x, y, z, mask[j] = value); - } - } - } - - public boolean isUnlit(byte[] array) { - for (byte val : array) { - if (val != 0) { - return false; - } - } - return true; - } - - private class RelightSkyEntry implements Comparable { - public final int x; - public final int z; - public final byte[] mask; - public final byte[] fix; - public int bitmask; - public boolean smooth; - - public RelightSkyEntry(int x, int z, byte[] fix, int bitmask) { - this.x = x; - this.z = z; - byte[] array = new byte[256]; - Arrays.fill(array, (byte) 15); - this.mask = array; - this.bitmask = bitmask; - if (fix == null) { - this.fix = new byte[(maxY + 1) >> 4]; - Arrays.fill(this.fix, SkipReason.NONE); - } else { - this.fix = fix; - } - } - - @Override - public String toString() { - return x + "," + z; - } - - @Override - public int compareTo(Object o) { - RelightSkyEntry other = (RelightSkyEntry) o; - if (other.x < x) { - return 1; - } - if (other.x > x) { - return -1; - } - if (other.z < z) { - return 1; - } - if (other.z > z) { - return -1; - } - return 0; - } - } -} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/example/NullFaweChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/example/NullFaweChunk.java deleted file mode 100644 index b3bba3396..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/example/NullFaweChunk.java +++ /dev/null @@ -1,113 +0,0 @@ -package com.boydti.fawe.example; - -import com.boydti.fawe.object.FaweChunk; -import com.boydti.fawe.object.FaweQueue; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BlockTypes; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - -public class NullFaweChunk extends FaweChunk { - public static final NullFaweChunk INSTANCE = new NullFaweChunk(null, 0, 0); - - /** - * A FaweSections object represents a chunk and the blocks that you wish to change in it. - * - * @param parent - * @param x - * @param z - */ - public NullFaweChunk(FaweQueue parent, int x, int z) { - super(parent, x, z); - } - - @Override - public int[][] getCombinedIdArrays() { - return new int[16][]; - } - - @Override - public int[] getIdArray(int layer) { - return null; - } - - @Override - public BiomeType[] getBiomeArray() { - return new BiomeType[256]; - } - - @Override - public int getBitMask() { - return 0; - } - - @Override - public int getBlockCombinedId(int x, int y, int z) { - return BlockTypes.AIR.getInternalId(); - } - - @Override - public Void getChunk() { - return null; - } - - @Override - public void setTile(int x, int y, int z, CompoundTag tile) { - - } - - @Override - public void setEntity(CompoundTag entity) { - - } - - @Override - public void removeEntity(UUID uuid) { - - } - - @Override - public void setBlock(int x, int y, int z, int combinedId) { - - } - - @Override - public Set getEntities() { - return new HashSet<>(); - } - - @Override - public Set getEntityRemoves() { - return new HashSet<>(); - } - - @Override - public Map getTiles() { - return new HashMap<>(); - } - - @Override - public CompoundTag getTile(int x, int y, int z) { - return null; - } - - @Override - public void setBiome(int x, int z, BiomeType biome) { - - } - - @Override - public FaweChunk copy(boolean shallow) { - return this; - } - - @Override - public FaweChunk call() { - return null; - } -} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/example/NullQueueIntFaweChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/example/NullQueueIntFaweChunk.java deleted file mode 100644 index f1c31df3f..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/example/NullQueueIntFaweChunk.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.boydti.fawe.example; - -import com.boydti.fawe.object.FaweChunk; -import com.boydti.fawe.util.MainUtil; - -public class NullQueueIntFaweChunk extends IntFaweChunk { - - public NullQueueIntFaweChunk(int cx, int cz) { - super(null, cx, cz); - } - - public NullQueueIntFaweChunk(int x, int z, int[][] ids, short[] count, short[] air) { - super(null, x, z, ids, count, air); - } - - @Override - public Object getNewChunk() { - return null; - } - - @Override - public IntFaweChunk copy(boolean shallow) { - if (shallow) { - return new NullQueueIntFaweChunk(getX(), getZ(), setBlocks, count, air); - } else { - return new NullQueueIntFaweChunk(getX(), getZ(), (int[][]) MainUtil.copyNd(setBlocks), count.clone(), air.clone()); - } - } - - @Override - public FaweChunk call() { - return null; - } -} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/example/NullRelighter.java b/worldedit-core/src/main/java/com/boydti/fawe/example/NullRelighter.java deleted file mode 100644 index 59ced0651..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/example/NullRelighter.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.boydti.fawe.example; - -public class NullRelighter implements Relighter { - - public static NullRelighter INSTANCE = new NullRelighter(); - - private NullRelighter() { - } - - @Override - public boolean addChunk(int cx, int cz, byte[] fix, int bitmask) { - return false; - } - - @Override - public void addLightUpdate(int x, int y, int z) { - - } - - @Override - public void fixLightingSafe(boolean sky) { - - } - - @Override - public void clear() { - - } - - @Override - public void removeLighting() { - - } - - @Override - public void fixBlockLighting() { - - } - - @Override - public void fixSkyLighting() { - - } - - @Override - public boolean isEmpty() { - return true; - } -} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/example/Relighter.java b/worldedit-core/src/main/java/com/boydti/fawe/example/Relighter.java deleted file mode 100644 index 82f5ea0b1..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/example/Relighter.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.boydti.fawe.example; - -public interface Relighter { - boolean addChunk(int cx, int cz, byte[] skipReason, int bitmask); - - void addLightUpdate(int x, int y, int z); - - void fixLightingSafe(boolean sky); - - default void removeAndRelight(boolean sky) { - removeLighting(); - fixLightingSafe(sky); - } - - void clear(); - - void removeLighting(); - - void fixBlockLighting(); - - void fixSkyLighting(); - - boolean isEmpty(); - - public static class SkipReason { - public static final byte NONE = 0; - public static final byte AIR = 1; - public static final byte SOLID = 2; - } -} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/example/SimpleIntFaweChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/example/SimpleIntFaweChunk.java deleted file mode 100644 index 6012e9782..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/example/SimpleIntFaweChunk.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.boydti.fawe.example; - -import com.boydti.fawe.object.FaweChunk; -import com.boydti.fawe.object.FaweQueue; -import com.boydti.fawe.util.MainUtil; - -public class SimpleIntFaweChunk extends IntFaweChunk { - - public SimpleIntFaweChunk(FaweQueue parent, int x, int z) { - super(parent, x, z); - } - - public SimpleIntFaweChunk(FaweQueue parent, int x, int z, int[][] ids, short[] count, short[] air) { - super(parent, x, z, ids, count, air); - } - - @Override - public Object getNewChunk() { - return this; - } - - @Override - public IntFaweChunk copy(boolean shallow) { - SimpleIntFaweChunk copy; - if (shallow) { - copy = new SimpleIntFaweChunk(getParent(), getX(), getZ(), setBlocks, count, air); - copy.biomes = biomes; - } else { - copy = new SimpleIntFaweChunk(getParent(), getX(), getZ(), (int[][]) MainUtil.copyNd(setBlocks), count.clone(), air.clone()); - copy.biomes = biomes != null ? biomes.clone() : null; - } - return copy; - } - - @Override - public FaweChunk call() { - getParent().setChunk(this); - return this; - } -} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/example/WeakFaweQueueMap.java b/worldedit-core/src/main/java/com/boydti/fawe/example/WeakFaweQueueMap.java deleted file mode 100644 index 0f2b4f808..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/example/WeakFaweQueueMap.java +++ /dev/null @@ -1,242 +0,0 @@ -package com.boydti.fawe.example; - -import com.boydti.fawe.Fawe; -import com.boydti.fawe.object.FaweChunk; -import com.boydti.fawe.object.FaweQueue; -import com.boydti.fawe.object.RunnableVal; -import com.boydti.fawe.util.MathMan; -import com.boydti.fawe.util.SetQueue; -import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -import java.lang.ref.Reference; -import java.lang.ref.SoftReference; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.concurrent.ExecutorCompletionService; -import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -public class WeakFaweQueueMap implements IFaweQueueMap { - - private final MappedFaweQueue parent; - - public WeakFaweQueueMap(MappedFaweQueue parent) { - this.parent = parent; - } - - public final Long2ObjectOpenHashMap> blocks = new Long2ObjectOpenHashMap>() { - @Override - public Reference put(Long key, Reference value) { - return put((long) key, value); - } - - @Override - public Reference put(long key, Reference value) { - if (parent.getProgressTask() != null) { - try { - parent.getProgressTask().run(FaweQueue.ProgressType.QUEUE, size()); - } catch (Throwable e) { - e.printStackTrace(); - } - } - synchronized (this) { - return super.put(key, value); - } - } - }; - - @Override - public Collection getFaweChunks() { - HashSet set = new HashSet<>(); - synchronized (blocks) { - Iterator>> iter = blocks.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry> entry = iter.next(); - FaweChunk value = entry.getValue().get(); - if (value != null) { - set.add(value); - } else { - Fawe.debug("Skipped modifying chunk due to low memory (1)"); - iter.remove(); - } - } - return set; - } - } - - @Override - public void forEachChunk(RunnableVal onEach) { - synchronized (blocks) { - Iterator>> iter = blocks.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry> entry = iter.next(); - FaweChunk value = entry.getValue().get(); - if (value != null) { - onEach.run(value); - } else { - Fawe.debug("Skipped modifying chunk due to low memory (2)"); - iter.remove(); - } - } - } - } - - @Override - public FaweChunk getFaweChunk(int cx, int cz) { - if (cx == lastX && cz == lastZ) { - return lastWrappedChunk; - } - long pair = MathMan.pairInt(cx, cz); - Reference chunkReference = this.blocks.get(pair); - FaweChunk chunk; - if (chunkReference == null || (chunk = chunkReference.get()) == null) { - chunk = this.getNewFaweChunk(cx, cz); - Reference previous = this.blocks.put(pair, new SoftReference(chunk)); - if (previous != null) { - FaweChunk tmp = previous.get(); - if (tmp != null) { - chunk = tmp; - this.blocks.put(pair, previous); - } - } - - } - return chunk; - } - - @Override - public FaweChunk getCachedFaweChunk(int cx, int cz) { - if (cx == lastX && cz == lastZ) { - return lastWrappedChunk; - } - long pair = MathMan.pairInt(cx, cz); - Reference reference = this.blocks.get(pair); - if (reference != null) { - return reference.get(); - } else { - return null; - } - } - - @Override - public void add(FaweChunk chunk) { - long pair = MathMan.pairInt(chunk.getX(), chunk.getZ()); - Reference previous = this.blocks.put(pair, new SoftReference<>(chunk)); - if (previous != null) { - FaweChunk previousChunk = previous.get(); - if (previousChunk != null) { - blocks.put(pair, previous); - } - } - } - - - @Override - public void clear() { - blocks.clear(); - } - - @Override - public int size() { - return blocks.size(); - } - - private FaweChunk getNewFaweChunk(int cx, int cz) { - return parent.getFaweChunk(cx, cz); - } - - private FaweChunk lastWrappedChunk; - private int lastX = Integer.MIN_VALUE; - private int lastZ = Integer.MIN_VALUE; - - @Override - public boolean next(int amount, long time) { - synchronized (blocks) { - try { - boolean skip = parent.getStage() == SetQueue.QueueStage.INACTIVE; - int added = 0; - Iterator>> iter = blocks.entrySet().iterator(); - if (amount == 1) { - long start = System.currentTimeMillis(); - do { - if (iter.hasNext()) { - Map.Entry> entry = iter.next(); - Reference chunkReference = entry.getValue(); - FaweChunk chunk = chunkReference.get(); - if (skip && chunk == lastWrappedChunk) { - continue; - } - iter.remove(); - if (chunk != null) { - parent.start(chunk); - chunk.call(); - parent.end(chunk); - } else { - Fawe.debug("Skipped modifying chunk due to low memory (3)"); - } - } else { - break; - } - } while (System.currentTimeMillis() - start < time); - return !blocks.isEmpty(); - } - ExecutorCompletionService service = SetQueue.IMP.getCompleterService(); - ForkJoinPool pool = SetQueue.IMP.getForkJoinPool(); - boolean result = true; - // amount = 8; - for (int i = 0; i < amount && (result = iter.hasNext()); ) { - Map.Entry> item = iter.next(); - Reference chunkReference = item.getValue(); - FaweChunk chunk = chunkReference.get(); - if (skip && chunk == lastWrappedChunk) { - continue; - } - iter.remove(); - if (chunk != null) { - parent.start(chunk); - service.submit(chunk); - added++; - i++; - } else { - Fawe.debug("Skipped modifying chunk due to low memory (4)"); - } - } - // if result, then submitted = amount - if (result) { - long start = System.currentTimeMillis(); - while (System.currentTimeMillis() - start < time && result) { - if (result = iter.hasNext()) { - Map.Entry> item = iter.next(); - Reference chunkReference = item.getValue(); - FaweChunk chunk = chunkReference.get(); - if (skip && chunk == lastWrappedChunk) { - continue; - } - iter.remove(); - if (chunk != null) { - parent.start(chunk); - service.submit(chunk); - Future future = service.poll(50, TimeUnit.MILLISECONDS); - if (future != null) { - FaweChunk fc = (FaweChunk) future.get(); - parent.end(fc); - } - } - } - } - } - pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS); - Future future; - while ((future = service.poll()) != null) { - FaweChunk fc = (FaweChunk) future.get(); - parent.end(fc); - } - } catch (Throwable e) { - e.printStackTrace(); - } - return !blocks.isEmpty(); - } - } -} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/NBTStreamer.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/NBTStreamer.java index fccbb34e8..8f5487204 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/NBTStreamer.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/NBTStreamer.java @@ -40,7 +40,7 @@ public class NBTStreamer { try { is.readNamedTagLazy(node -> { if (readers.isEmpty()) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MANUAL); + throw FaweException.MANUAL; } return readers.remove(node); }); @@ -55,12 +55,6 @@ public class NBTStreamer { readers.put(node, run); } - public void addReader(BiConsumer run, String... nodes) { - for (String node : nodes) { - addReader(node, run); - } - } - public static abstract class NBTStreamReader implements BiConsumer { private String node; @@ -82,7 +76,7 @@ public class NBTStreamer { public abstract void run(int index, int byteValue); } - public static abstract class LazyReader implements BiConsumer {} + public interface LazyReader extends BiConsumer {} public static abstract class LongReader implements BiConsumer { @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/SchematicStreamer.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/SchematicStreamer.java index 047c120e7..6dfd09a37 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/SchematicStreamer.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/SchematicStreamer.java @@ -57,21 +57,21 @@ public class SchematicStreamer extends NBTStreamer { } public void addBlockReaders() throws IOException { - NBTStreamReader idInit = new NBTStreamReader() { + NBTStreamReader idInit = new NBTStreamReader() { @Override public void accept(Integer length, Integer type) { setupClipboard(length); ids = new FaweOutputStream(new LZ4BlockOutputStream(idOut)); } }; - NBTStreamReader dataInit = new NBTStreamReader() { + NBTStreamReader dataInit = new NBTStreamReader() { @Override public void accept(Integer length, Integer type) { setupClipboard(length); datas = new FaweOutputStream(new LZ4BlockOutputStream(dataOut)); } }; - NBTStreamReader addInit = new NBTStreamReader() { + NBTStreamReader addInit = new NBTStreamReader() { @Override public void accept(Integer length, Integer type) { setupClipboard(length*2); @@ -225,19 +225,19 @@ public class SchematicStreamer extends NBTStreamer { Direction left = facing.getLeft(); Direction right = facing.getRight(); - BlockStateHolder forwardBlock = fc.getBlock(x + forward.getBlockX(), y + forward.getBlockY(), z + forward.getBlockZ()); + BlockStateHolder forwardBlock = fc.getBlock(x + forward.getBlockX(), y + forward.getBlockY(), z + forward.getBlockZ()); BlockType forwardType = forwardBlock.getBlockType(); if (forwardType.hasProperty(PropertyKey.SHAPE) && forwardType.hasProperty(PropertyKey.FACING)) { Direction forwardFacing = (Direction) forwardBlock.getState(PropertyKey.FACING); if (forwardFacing == left) { - BlockStateHolder rightBlock = fc.getBlock(x + right.toBlockVector().getBlockX(), y + right.toBlockVector().getBlockY(), z + right.toBlockVector().getBlockZ()); + BlockStateHolder rightBlock = fc.getBlock(x + right.toBlockVector().getBlockX(), y + right.toBlockVector().getBlockY(), z + right.toBlockVector().getBlockZ()); BlockType rightType = rightBlock.getBlockType(); if (!rightType.hasProperty(PropertyKey.SHAPE) || rightBlock.getState(PropertyKey.FACING) != facing) { fc.setBlock(x, y, z, block.with(PropertyKey.SHAPE, "inner_left")); } return; } else if (forwardFacing == right) { - BlockStateHolder leftBlock = fc.getBlock(x + left.toBlockVector().getBlockX(), y + left.toBlockVector().getBlockY(), z + left.toBlockVector().getBlockZ()); + BlockStateHolder leftBlock = fc.getBlock(x + left.toBlockVector().getBlockX(), y + left.toBlockVector().getBlockY(), z + left.toBlockVector().getBlockZ()); BlockType leftType = leftBlock.getBlockType(); if (!leftType.hasProperty(PropertyKey.SHAPE) || leftBlock.getState(PropertyKey.FACING) != facing) { fc.setBlock(x, y, z, block.with(PropertyKey.SHAPE, "inner_right")); @@ -246,19 +246,19 @@ public class SchematicStreamer extends NBTStreamer { } } - BlockStateHolder backwardsBlock = fc.getBlock(x - forward.getBlockX(), y - forward.getBlockY(), z - forward.getBlockZ()); + BlockStateHolder backwardsBlock = fc.getBlock(x - forward.getBlockX(), y - forward.getBlockY(), z - forward.getBlockZ()); BlockType backwardsType = backwardsBlock.getBlockType(); if (backwardsType.hasProperty(PropertyKey.SHAPE) && backwardsType.hasProperty(PropertyKey.FACING)) { Direction backwardsFacing = (Direction) backwardsBlock.getState(PropertyKey.FACING); if (backwardsFacing == left) { - BlockStateHolder rightBlock = fc.getBlock(x + right.toBlockVector().getBlockX(), y + right.toBlockVector().getBlockY(), z + right.toBlockVector().getBlockZ()); + BlockStateHolder rightBlock = fc.getBlock(x + right.toBlockVector().getBlockX(), y + right.toBlockVector().getBlockY(), z + right.toBlockVector().getBlockZ()); BlockType rightType = rightBlock.getBlockType(); if (!rightType.hasProperty(PropertyKey.SHAPE) || rightBlock.getState(PropertyKey.FACING) != facing) { fc.setBlock(x, y, z, block.with(PropertyKey.SHAPE, "outer_left")); } return; } else if (backwardsFacing == right) { - BlockStateHolder leftBlock = fc.getBlock(x + left.toBlockVector().getBlockX(), y + left.toBlockVector().getBlockY(), z + left.toBlockVector().getBlockZ()); + BlockStateHolder leftBlock = fc.getBlock(x + left.toBlockVector().getBlockX(), y + left.toBlockVector().getBlockY(), z + left.toBlockVector().getBlockZ()); BlockType leftType = leftBlock.getBlockType(); if (!leftType.hasProperty(PropertyKey.SHAPE) || leftBlock.getState(PropertyKey.FACING) != facing) { fc.setBlock(x, y, z, block.with(PropertyKey.SHAPE, "outer_right")); @@ -298,7 +298,7 @@ public class SchematicStreamer extends NBTStreamer { }, true).build(); private boolean merge(int group, int x, int y, int z) { - BlockStateHolder block = fc.getBlock(x, y, z); + BlockStateHolder block = fc.getBlock(x, y, z); BlockType type = block.getBlockType(); return group(type) == group || fullCube.apply(type); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/BitArray4096.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/BitArray4096.java index d0a93bcc8..c590f3138 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/BitArray4096.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/BitArray4096.java @@ -14,7 +14,6 @@ public final class BitArray4096 { maxEntryValue = (1 << bitsPerEntry) - 1; this.longLen = (this.bitsPerEntry * 4096) >> 6; if (buffer.length < longLen) { - System.out.println("Invalid buffer " + buffer.length + " | " + longLen); this.data = new long[longLen]; } else { this.data = buffer; @@ -159,4 +158,38 @@ public final class BitArray4096 { } return buffer; } + + public final char[] toRaw(char[] buffer) { + final long[] data = this.data; + final int dataLength = longLen; + final int bitsPerEntry = this.bitsPerEntry; + final int maxEntryValue = this.maxEntryValue; + final int maxSeqLocIndex = this.maxSeqLocIndex; + + int localStart = 0; + char lastVal; + int arrI = 0; + long l; + for (int i = 0; i < dataLength; i++) { + l = data[i]; + for (; localStart <= maxSeqLocIndex; localStart += bitsPerEntry) { + lastVal = (char) (l >>> localStart & maxEntryValue); + buffer[arrI++] = lastVal; + } + if (localStart < 64) { + if (i != dataLength - 1) { + lastVal = (char) (l >>> localStart); + localStart -= maxSeqLocIndex; + l = data[i + 1]; + int localShift = bitsPerEntry - localStart; + lastVal |= l << localShift; + lastVal &= maxEntryValue; + buffer[arrI++] = lastVal; + } + } else { + localStart = 0; + } + } + return buffer; + } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAFile.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAFile.java index b274b241c..4bac59bac 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAFile.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAFile.java @@ -79,7 +79,7 @@ public class MCAFile { this.queue = parent; this.file = file; if (!file.exists()) { - throw new FaweException.FaweChunkLoadException(); + throw FaweException.CHUNK; } String[] split = file.getName().split("\\."); X = Integer.parseInt(split[1]); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAWorld.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAWorld.java index ab6701b0d..4c8926103 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAWorld.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAWorld.java @@ -104,7 +104,7 @@ public class MCAWorld implements SimpleWorld { @Override public BlockState getBlock(BlockVector3 position) { - return extent.getLazyBlock(position); + return extent.getBlock(position); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAWriter.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAWriter.java index 19f34b0ab..b05318592 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAWriter.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAWriter.java @@ -3,6 +3,7 @@ package com.boydti.fawe.jnbt.anvil; import com.boydti.fawe.object.collection.IterableThreadLocal; import com.boydti.fawe.object.io.BufferedRandomAccessFile; import com.boydti.fawe.util.MainUtil; +import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.world.block.BlockID; import java.io.File; @@ -12,7 +13,7 @@ import java.util.concurrent.ForkJoinPool; import java.util.concurrent.TimeUnit; import java.util.zip.Deflater; -public abstract class MCAWriter { +public abstract class MCAWriter implements Extent { private File folder; private final int length; private final int width; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/generator/CavesGen.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/generator/CavesGen.java index 25e4bb415..4c76a6c86 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/generator/CavesGen.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/generator/CavesGen.java @@ -149,7 +149,7 @@ public class CavesGen extends GenBase { for (int local_z = i3; (!waterFound) && (local_z < i4); local_z++) { for (int local_y = i2 + 1; (!waterFound) && (local_y >= i1 - 1); local_y--) { if (local_y < 255) { - BlockStateHolder material = chunk.getLazyBlock(bx + local_x, local_y, bz + local_z); + BlockStateHolder material = chunk.getBlock(bx + local_x, local_y, bz + local_z); if (material.getBlockType() == BlockTypes.WATER) { waterFound = true; } @@ -173,8 +173,8 @@ public class CavesGen extends GenBase { for (int local_y = i2; local_y > i1; local_y--) { double d11 = ((local_y - 1) + 0.5D - y) / d4; if ((d11 > -0.7D) && (d9 * d9 + d11 * d11 + d10 * d10 < 1.0D)) { - BlockStateHolder material = chunk.getLazyBlock(bx + local_x, local_y, bz + local_z); - BlockStateHolder materialAbove = chunk.getLazyBlock(bx + local_x, local_y + 1, bz + local_z); + BlockStateHolder material = chunk.getBlock(bx + local_x, local_y, bz + local_z); + BlockStateHolder materialAbove = chunk.getBlock(bx + local_x, local_y + 1, bz + local_z); BlockType blockType = material.getBlockType(); switch (blockType.getInternalId()) { case BlockID.MYCELIUM: @@ -191,7 +191,7 @@ public class CavesGen extends GenBase { // If grass was just deleted, try to // move it down if (grassFound) { - BlockStateHolder block = chunk.getLazyBlock(bx + local_x, local_y - 1, bz + local_z); + BlockStateHolder block = chunk.getBlock(bx + local_x, local_y - 1, bz + local_z); if (block.getBlockType() == BlockTypes.DIRT) { chunk.setBlock(bx + local_x, local_y - 1, bz + local_z, BlockTypes.STONE.getDefaultState()); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/generator/OreGen.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/generator/OreGen.java index 7ded48ea7..86c6ad7cd 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/generator/OreGen.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/generator/OreGen.java @@ -9,7 +9,7 @@ import com.sk89q.worldedit.math.MutableBlockVector3; import java.util.Random; -public class OreGen extends Resource { +public class OreGen implements Resource { private final int maxSize; private final double maxSizeO8; private final double maxSizeO16; @@ -21,9 +21,9 @@ public class OreGen extends Resource { private final Mask mask; private MutableBlockVector3 mutable = new MutableBlockVector3(); - private double ONE_2 = 1 / 2F; - private double ONE_8 = 1 / 8F; - private double ONE_16 = 1 / 16F; + private final double ONE_2 = 1 / 2F; + private final double ONE_8 = 1 / 8F; + private final double ONE_16 = 1 / 16F; public int laced = 0; @@ -47,16 +47,13 @@ public class OreGen extends Resource { } double f = rand.nextDouble() * Math.PI; - int x8 = x; - int z8 = z; double so8 = maxSizeO8; - double so16 = maxSizeO16; double sf = MathMan.sinInexact(f) * so8; double cf = MathMan.cosInexact(f) * so8; - double d1 = x8 + sf; - double d2 = x8 - sf; - double d3 = z8 + cf; - double d4 = z8 - cf; + double d1 = x + sf; + double d2 = x - sf; + double d3 = z + cf; + double d4 = z - cf; double d5 = y + rand.nextInt(3) - 2; double d6 = y + rand.nextInt(3) - 2; @@ -71,7 +68,7 @@ public class OreGen extends Resource { double d8 = d5 + yd * iFactor; double d9 = d3 + zd * iFactor; - double d10 = rand.nextDouble() * so16; + double d10 = rand.nextDouble() * maxSizeO16; double sif = MathMan.sinInexact(Math.PI * iFactor); double d11 = (sif + 1.0) * d10 + 1.0; double d12 = (sif + 1.0) * d10 + 1.0; @@ -116,4 +113,4 @@ public class OreGen extends Resource { } return true; } -} \ No newline at end of file +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/generator/Resource.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/generator/Resource.java index 9ff294afd..b7f96a62d 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/generator/Resource.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/generator/Resource.java @@ -4,8 +4,7 @@ import com.sk89q.worldedit.WorldEditException; import java.util.Random; -public abstract class Resource { - public Resource() {} +public interface Resource { - public abstract boolean spawn(Random random, int x, int z) throws WorldEditException; + boolean spawn(Random random, int x, int z) throws WorldEditException; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/generator/SchemGen.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/generator/SchemGen.java index 3cb58d0af..849cff90c 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/generator/SchemGen.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/generator/SchemGen.java @@ -13,7 +13,7 @@ import java.util.List; import java.util.Random; import java.util.concurrent.ThreadLocalRandom; -public class SchemGen extends Resource { +public class SchemGen implements Resource { private final Extent extent; private final List clipboards; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/DataAnglePattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/DataAnglePattern.java index 323e918e3..48696a6d0 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/DataAnglePattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/DataAnglePattern.java @@ -1,15 +1,14 @@ package com.boydti.fawe.object; -import com.boydti.fawe.FaweCache; +import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.object.extent.ExtentHeightCacher; import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.AbstractPattern; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; -import com.sk89q.worldedit.world.block.BlockTypes; public class DataAnglePattern extends AbstractPattern { public final double FACTOR; @@ -24,7 +23,7 @@ public class DataAnglePattern extends AbstractPattern { this.FACTOR = (1D / distance) * (1D / 255); } - public int getSlope(BlockStateHolder block, BlockVector3 vector) { + public int getSlope(BlockStateHolder block, BlockVector3 vector, Extent extent) { int x = vector.getBlockX(); int y = vector.getBlockY(); int z = vector.getBlockZ(); @@ -32,7 +31,6 @@ public class DataAnglePattern extends AbstractPattern { return -1; } int slope; - boolean aboveMin; slope = Math.abs(extent.getNearestSurfaceTerrainBlock(x + distance, z, y, 0, maxY) - extent.getNearestSurfaceTerrainBlock(x - distance, z, y, 0, maxY)) * 7; slope += Math.abs(extent.getNearestSurfaceTerrainBlock(x, z + distance, y, 0, maxY) - extent.getNearestSurfaceTerrainBlock(x, z - distance, y, 0, maxY)) * 7; slope += Math.abs(extent.getNearestSurfaceTerrainBlock(x + distance, z + distance, y, 0, maxY) - extent.getNearestSurfaceTerrainBlock(x - distance, z - distance, y, 0, maxY)) * 5; @@ -42,8 +40,8 @@ public class DataAnglePattern extends AbstractPattern { @Override public BaseBlock apply(BlockVector3 position) { - BlockStateHolder block = extent.getBlock(position); - int slope = getSlope(block, position); + BlockState block = extent.getBlock(position); + int slope = getSlope(block, position, extent); if (slope == -1) return block.toBaseBlock(); int data = (Math.min(slope, 255)) >> 4; return block.withPropertyId(data).toBaseBlock(); @@ -52,7 +50,7 @@ public class DataAnglePattern extends AbstractPattern { @Override public boolean apply(Extent extent, BlockVector3 setPosition, BlockVector3 getPosition) throws WorldEditException { BlockStateHolder block = extent.getBlock(getPosition); - int slope = getSlope(block, getPosition); + int slope = getSlope(block, getPosition, extent); if (slope == -1) return false; int data = (Math.min(slope, 255)) >> 4; return extent.setBlock(setPosition, block.withPropertyId(data)); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/FaweChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/object/FaweChunk.java deleted file mode 100644 index 94471f67b..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/FaweChunk.java +++ /dev/null @@ -1,310 +0,0 @@ -package com.boydti.fawe.object; - -import com.boydti.fawe.object.visitor.FaweChunkVisitor; - -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BlockStateHolder; - -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.Callable; -import javax.annotation.Nullable; - -public abstract class FaweChunk implements Callable { - public static int HEIGHT = 256; - - private FaweQueue parent; - private int x, z; - - /** - * A FaweSections object represents a chunk and the blocks that you wish to change in it. - */ - public FaweChunk(FaweQueue parent, int x, int z) { - this.parent = parent; - this.x = x; - this.z = z; - } - - /** - * Change the chunk's location
- * - E.g. if you are cloning a chunk and want to set multiple - * - * @param parent - * @param x - * @param z - */ - public void setLoc(FaweQueue parent, int x, int z) { - this.parent = parent; - this.x = x; - this.z = z; - } - - /** - * Get the parent queue this chunk belongs to - * - * @return - */ - public FaweQueue getParent() { - return parent; - } - - public int getX() { - return x; - } - - public int getZ() { - return z; - } - - /** - * Get a unique hashcode for this chunk - * - * @return - */ - public long longHash() { - return (long) x << 32 | z & 0xFFFFFFFFL; - } - - /** - * Get a hashcode; unique below abs(x/z) < Short.MAX_VALUE - * - * @return - */ - @Override - public int hashCode() { - return x << 16 | z & 0xFFFF; - } - - /** - * Add the chunk to the queue - */ - public void addToQueue() { - parent.setChunk(this); - } - - /** - * The modified sections - * - * @return - */ - public abstract int getBitMask(); - - /** - * Get the combined block id at a location
- * combined = (id <<<< 4) + data - * - * @param x - * @param y - * @param z - * @return The combined id - */ - public abstract int getBlockCombinedId(int x, int y, int z); - - public > void setBlock(int x, int y, int z, B block) { - setBlock(x, y, z, block.getInternalId()); - if (block instanceof BaseBlock && ((BaseBlock)block).hasNbtData()) { - setTile(x & 15, y, z & 15, ((BaseBlock)block).getNbtData()); - } - } - - public BlockState getBlock(int x, int y, int z) { - int combined = getBlockCombinedId(x, y, z); - // TODO FIXME optimize get nbt - try { - CompoundTag tile = getTile(x & 15, y, z & 15); - if (tile != null) { - return BaseBlock.getFromInternalId(combined, tile).toImmutableState(); - } - } catch (Throwable e) { - e.printStackTrace(); - } - return BlockState.getFromInternalId(combined); - } - - public int[][] getCombinedIdArrays() { - int[][] ids = new int[HEIGHT >> 4][]; - for (int layer = 0; layer < HEIGHT >> 4; layer++) { - ids[layer] = getIdArray(layer); - } - return ids; - } - - /** - * Get the combined id array at a layer or null if it does not exist - * - * @param layer - * @return int[] or null - */ - public - @Nullable - int[] getIdArray(int layer) { - int[] ids = new int[4096]; - int by = layer << 4; - int index = 0; - for (int y = 0; y < 16; y++) { - int yy = by + y; - for (int z = 0; z < 16; z++) { - for (int x = 0; x < 16; x++) { - ids[index++] = getBlockCombinedId(x, yy, z); - } - } - } - return ids; - } - - public byte[][] getBlockLightArray() { - return null; - } - - public byte[][] getSkyLightArray() { - return null; - } - - public abstract BiomeType[] getBiomeArray(); - - public BiomeType getBiomeType(int x, int z) { - return getBiomeArray()[(x & 15) + ((z & 15) << 4)]; - } - - public void forEachQueuedBlock(FaweChunkVisitor onEach) { - for (int y = 0; y < HEIGHT; y++) { - for (int z = 0; z < 16; z++) { - for (int x = 0; x < 16; x++) { - int combined = getBlockCombinedId(x, y, z); - if (combined == 0) { - continue; - } - onEach.run(x, y, z, combined); - } - } - } - } - - /** - * Fill this chunk with a block - * - * @param combinedId - */ - public void fill(int combinedId) { - fillCuboid(0, 15, 0, HEIGHT - 1, 0, 15, combinedId); - } - - /** - * Fill a cuboid in this chunk with a block - * - * @param x1 - * @param x2 - * @param y1 - * @param y2 - * @param z1 - * @param z2 - * @param combinedId - */ - public void fillCuboid(int x1, int x2, int y1, int y2, int z1, int z2, int combinedId) { - for (int x = x1; x <= x2; x++) { - for (int y = y1; y <= y2; y++) { - for (int z = z1; z <= z2; z++) { - setBlock(x, y, z, combinedId); - } - } - } - } - - /** - * Get the underlying chunk object - * - * @return - */ - public abstract T getChunk(); - - /** - * Set a tile entity at a location
- * - May throw an error if an invalid block is at the location - * - * @param x - * @param y - * @param z - * @param tile - */ - public abstract void setTile(int x, int y, int z, CompoundTag tile); - - public abstract void setEntity(CompoundTag entity); - - public abstract void removeEntity(UUID uuid); - - public abstract void setBlock(int x, int y, int z, int combinedId); - - public abstract Set getEntities(); - - /** - * Get the UUID of entities being removed - * - * @return - */ - public abstract Set getEntityRemoves(); - - /** - * Get the map of location to tile entity
- * - The byte pair represents the location in the chunk
- * - * @return - * @see com.boydti.fawe.util.MathMan#unpair16x (get0) => x - * @see com.boydti.fawe.util.MathMan#unpair16y (get0) => z - * get1 => y - */ - public abstract Map getTiles(); - - /** - * Get the tile at a location - * - * @param x - * @param y - * @param z - * @return - */ - public abstract CompoundTag getTile(int x, int y, int z); - - public abstract void setBiome(final int x, final int z, final BiomeType biome); - - public void setBiome(final BiomeType biome) { - for (int z = 0; z < 16; z++) { - for (int x = 0; x < 16; x++) { - setBiome(x, z, biome); - } - } - } - - /** - * Spend time now so that the chunk can be more efficiently dispatched later
- * - Modifications after this call will be ignored - */ - public void optimize() { - } - - @Override - public boolean equals(final Object obj) { - if ((obj == null) || obj.hashCode() != hashCode() || !(obj instanceof FaweChunk)) { - return false; - } - return longHash() != ((FaweChunk) obj).longHash(); - } - - public abstract FaweChunk copy(boolean shallow); - - public void start() { - } - - ; - - public void end() { - } - - ; - - @Override - public abstract FaweChunk call(); -} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/FawePlayer.java b/worldedit-core/src/main/java/com/boydti/fawe/object/FawePlayer.java index 73bc3768f..919014d9c 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/FawePlayer.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/FawePlayer.java @@ -236,9 +236,9 @@ public abstract class FawePlayer extends Metadatable { Region[] allowed = WEManager.IMP.getMask(this, FaweMaskManager.MaskType.OWNER); HashSet allowedSet = new HashSet<>(Arrays.asList(allowed)); if (allowed.length == 0) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_NO_REGION); + throw FaweException.NO_REGION; } else if (!WEManager.IMP.regionContains(wrappedSelection, allowedSet)) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); + throw FaweException.OUTSIDE_REGION; } } @@ -661,39 +661,4 @@ public abstract class FawePlayer extends Metadatable { } return proxy; } - - - /** - * Get the tracked EditSession(s) for this player
- * - Queued or autoqueued EditSessions are considered tracked - * - * @param requiredStage - * @return - */ - public Map getTrackedSessions(SetQueue.QueueStage requiredStage) { - Map map = new ConcurrentHashMap<>(8, 0.9f, 1); - if (requiredStage == null || requiredStage == SetQueue.QueueStage.ACTIVE) { - for (FaweQueue queue : SetQueue.IMP.getActiveQueues()) { - Collection sessions = queue.getEditSessions(); - for (EditSession session : sessions) { - FawePlayer currentPlayer = session.getPlayer(); - if (currentPlayer == this) { - map.put(session, SetQueue.QueueStage.ACTIVE); - } - } - } - } - if (requiredStage == null || requiredStage == SetQueue.QueueStage.INACTIVE) { - for (FaweQueue queue : SetQueue.IMP.getInactiveQueues()) { - Collection sessions = queue.getEditSessions(); - for (EditSession session : sessions) { - FawePlayer currentPlayer = session.getPlayer(); - if (currentPlayer == this) { - map.put(session, SetQueue.QueueStage.INACTIVE); - } - } - } - } - return map; - } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/HasFaweQueue.java b/worldedit-core/src/main/java/com/boydti/fawe/object/HasFaweQueue.java deleted file mode 100644 index 8ad5b840f..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/HasFaweQueue.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.boydti.fawe.object; - -public interface HasFaweQueue { - FaweQueue getQueue(); -} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/HistoryExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/HistoryExtent.java index 83e26f098..058724112 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/HistoryExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/HistoryExtent.java @@ -29,7 +29,6 @@ public class HistoryExtent extends AbstractDelegateExtent { private FaweChangeSet changeSet; private final FaweQueue queue; - private final EditSession session; /** * Create a new instance. @@ -37,12 +36,11 @@ public class HistoryExtent extends AbstractDelegateExtent { * @param extent the extent * @param changeSet the change set */ - public HistoryExtent(final EditSession session, final Extent extent, final FaweChangeSet changeSet, FaweQueue queue) { + public HistoryExtent(final Extent extent, final FaweChangeSet changeSet, FaweQueue queue) { super(extent); checkNotNull(changeSet); this.queue = queue; this.changeSet = changeSet; - this.session = session; } public FaweChangeSet getChangeSet() { @@ -55,9 +53,9 @@ public class HistoryExtent extends AbstractDelegateExtent { @Override public > boolean setBlock(int x, int y, int z, B block) throws WorldEditException { - BaseBlock previous = queue.getFullBlock(mutable.setComponents(x, y, z)).toBaseBlock(); + BaseBlock previous = queue.getFullBlock(x, y, z); if (previous.getInternalId() == block.getInternalId()) { - if (!previous.hasNbtData() && (block instanceof BaseBlock && !((BaseBlock)block).hasNbtData())) { + if (!previous.hasNbtData() && (block instanceof BaseBlock && !block.hasNbtData())) { return false; } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/NullChangeSet.java b/worldedit-core/src/main/java/com/boydti/fawe/object/NullChangeSet.java index c7d5d931d..baecc2148 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/NullChangeSet.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/NullChangeSet.java @@ -53,11 +53,6 @@ public class NullChangeSet extends FaweChangeSet { } - @Override - public void addChangeTask(FaweQueue queue) { - - } - @Override public Iterator getIterator(BlockBag blockBag, int mode, boolean redo) { return getIterator(redo); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/LayerBrush.java b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/LayerBrush.java index fccf2502c..41039fb55 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/LayerBrush.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/LayerBrush.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.brush; +import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.object.collection.BlockVectorSet; import com.boydti.fawe.object.mask.AdjacentAnyMask; @@ -7,6 +8,7 @@ import com.boydti.fawe.object.mask.RadiusMask; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.command.tool.brush.Brush; +import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.function.mask.BlockTypeMask; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.SolidBlockMask; @@ -34,7 +36,7 @@ public class LayerBrush implements Brush { @Override public void build(EditSession editSession, BlockVector3 position, Pattern ignore, double size) throws MaxChangedBlocksException { final FaweQueue queue = editSession.getQueue(); - final AdjacentAnyMask adjacent = new AdjacentAnyMask(new BlockTypeMask(editSession, BlockTypes.AIR, BlockTypes.CAVE_AIR, BlockTypes.VOID_AIR)); + final AdjacentAnyMask adjacent = new AdjacentAnyMask(new BlockMask(editSession).add(BlockTypes.AIR, BlockTypes.CAVE_AIR, BlockTypes.VOID_AIR)); final SolidBlockMask solid = new SolidBlockMask(editSession); final RadiusMask radius = new RadiusMask(0, (int) size); visitor = new RecursiveVisitor(vector -> solid.test(vector) && radius.test(vector) && adjacent.test(vector), function -> true); @@ -42,30 +44,32 @@ public class LayerBrush implements Brush { visitor.setDirections(Arrays.asList(BreadthFirstSearch.DIAGONAL_DIRECTIONS)); Operations.completeBlindly(visitor); BlockVectorSet visited = visitor.getVisited(); - BlockStateHolder firstPattern = layers[0]; - visitor = new RecursiveVisitor((Mask) pos -> { - int depth = visitor.getDepth() + 1; - if (depth > 1) { - boolean found = false; - int previous = layers[depth - 1].getInternalId(); - int previous2 = layers[depth - 2].getInternalId(); - for (BlockVector3 dir : BreadthFirstSearch.DEFAULT_DIRECTIONS) { - mutable.setComponents(pos.getBlockX() + dir.getBlockX(), pos.getBlockY() + dir.getBlockY(), pos.getBlockZ() + dir.getBlockZ()); - if (visitor.isVisited(mutable) && queue.getCachedCombinedId4Data(mutable.getBlockX(), mutable.getBlockY(), mutable.getBlockZ()) == previous) { - mutable.setComponents(pos.getBlockX() + dir.getBlockX() * 2, pos.getBlockY() + dir.getBlockY() * 2, pos.getBlockZ() + dir.getBlockZ() * 2); - if (visitor.isVisited(mutable) && queue.getCachedCombinedId4Data(mutable.getBlockX(), mutable.getBlockY(), mutable.getBlockZ()) == previous2) { - found = true; - break; - } else { - return false; + visitor = new RecursiveVisitor(new Mask() { + @Override + public boolean test(BlockVector3 pos) { + int depth = visitor.getDepth() + 1; + if (depth > 1) { + boolean found = false; + int previous = layers[depth - 1].getInternalId(); + int previous2 = layers[depth - 2].getInternalId(); + for (BlockVector3 dir : BreadthFirstSearch.DEFAULT_DIRECTIONS) { + mutable.setComponents(pos.getBlockX() + dir.getBlockX(), pos.getBlockY() + dir.getBlockY(), pos.getBlockZ() + dir.getBlockZ()); + if (visitor.isVisited(mutable) && queue.getCachedCombinedId4Data(mutable.getBlockX(), mutable.getBlockY(), mutable.getBlockZ()) == previous) { + mutable.setComponents(pos.getBlockX() + dir.getBlockX() * 2, pos.getBlockY() + dir.getBlockY() * 2, pos.getBlockZ() + dir.getBlockZ() * 2); + if (visitor.isVisited(mutable) && queue.getCachedCombinedId4Data(mutable.getBlockX(), mutable.getBlockY(), mutable.getBlockZ()) == previous2) { + found = true; + break; + } else { + return false; + } } } + if (!found) { + return false; + } } - if (!found) { - return false; - } + return !adjacent.test(pos); } - return !adjacent.test(pos); }, pos -> { int depth = visitor.getDepth(); BlockStateHolder currentPattern = layers[depth]; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/ShatterBrush.java b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/ShatterBrush.java index 70360ad15..62b78f249 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/ShatterBrush.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/ShatterBrush.java @@ -27,8 +27,6 @@ public class ShatterBrush extends ScatterBrush { @Override public void finish(EditSession editSession, LocalBlockVectorSet placed, final BlockVector3 position, Pattern pattern, double size) { int radius2 = (int) (size * size); - // Keep track of where we've visited - LocalBlockVectorSet tmp = new LocalBlockVectorSet(); // Individual frontier for each point LocalBlockVectorSet[] frontiers = new LocalBlockVectorSet[placed.size()]; // Keep track of where each frontier has visited @@ -51,6 +49,8 @@ public class ShatterBrush extends ScatterBrush { final SurfaceMask surfaceTest = new SurfaceMask(editSession); // Expand boolean notEmpty = true; + // Keep track of where we've visited + LocalBlockVectorSet tmp = new LocalBlockVectorSet(); while (notEmpty) { notEmpty = false; for (i = 0; i < frontiers.length; i++) { @@ -59,37 +59,33 @@ public class ShatterBrush extends ScatterBrush { final LocalBlockVectorSet frontierVisited = frontiersVisited[i]; // This is a temporary set with the next blocks the frontier will visit final LocalBlockVectorSet finalTmp = tmp; - frontier.forEach(new LocalBlockVectorSet.BlockVectorSetVisitor() { - @Override - public void run(int x, int y, int z, int index) { - if (ThreadLocalRandom.current().nextInt(2) == 0) { - finalTmp.add(x, y, z); - return; - } - for (int i = 0; i < BreadthFirstSearch.DIAGONAL_DIRECTIONS.length; i++) { - BlockVector3 direction = BreadthFirstSearch.DIAGONAL_DIRECTIONS[i]; - int x2 = x + direction.getBlockX(); - int y2 = y + direction.getBlockY(); - int z2 = z + direction.getBlockZ(); - // Check boundary - int dx = position.getBlockX() - x2; - int dy = position.getBlockY() - y2; - int dz = position.getBlockZ() - z2; - int dSqr = (dx * dx) + (dy * dy) + (dz * dz); - if (dSqr <= radius2) { - MutableBlockVector3 v = mutable.setComponents(x2, y2, z2); - BlockVector3 bv = v; - if (surfaceTest.test(bv) && finalMask.test(bv)) { - // (collision) If it's visited and part of another frontier, set the block - if (!placed.add(x2, y2, z2)) { - if (!frontierVisited.contains(x2, y2, z2)) { - editSession.setBlock(x2, y2, z2, pattern); - } - } else { - // Hasn't visited and not a collision = add it - finalTmp.add(x2, y2, z2); - frontierVisited.add(x2, y2, z2); + frontier.forEach((x, y, z, index) -> { + if (ThreadLocalRandom.current().nextInt(2) == 0) { + finalTmp.add(x, y, z); + return; + } + for (int i1 = 0; i1 < BreadthFirstSearch.DIAGONAL_DIRECTIONS.length; i1++) { + BlockVector3 direction = BreadthFirstSearch.DIAGONAL_DIRECTIONS[i1]; + int x2 = x + direction.getBlockX(); + int y2 = y + direction.getBlockY(); + int z2 = z + direction.getBlockZ(); + // Check boundary + int dx = position.getBlockX() - x2; + int dy = position.getBlockY() - y2; + int dz = position.getBlockZ() - z2; + int dSqr = (dx * dx) + (dy * dy) + (dz * dz); + if (dSqr <= radius2) { + BlockVector3 bv = mutable.setComponents(x2, y2, z2); + if (surfaceTest.test(bv) && finalMask.test(bv)) { + // (collision) If it's visited and part of another frontier, set the block + if (!placed.add(x2, y2, z2)) { + if (!frontierVisited.contains(x2, y2, z2)) { + editSession.setBlock(x2, y2, z2, pattern); } + } else { + // Hasn't visited and not a collision = add it + finalTmp.add(x2, y2, z2); + frontierVisited.add(x2, y2, z2); } } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/SplineBrush.java b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/SplineBrush.java index c4f7d817d..a021c1782 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/SplineBrush.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/SplineBrush.java @@ -68,7 +68,7 @@ public class SplineBrush implements Brush, ResettableTool { this.position = position; if (newPos) { if (positionSets.size() >= MAX_POINTS) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); + throw FaweException.MAX_CHECKS; } final ArrayList points = new ArrayList<>(); if (size > 0) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/SurfaceSpline.java b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/SurfaceSpline.java index 3e6ea0c6b..d6c1c37f5 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/SurfaceSpline.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/SurfaceSpline.java @@ -50,6 +50,7 @@ public class SurfaceSpline implements Brush { n.setContinuity(continuity); nodes.add(n); } + MutableBlockVector3 mutable = MutableBlockVector3.at(0, 0, 0); interpol.setNodes(nodes); final double splinelength = interpol.arcLength(0, 1); for (double loop = 0; loop <= 1; loop += 1D / splinelength / quality) { @@ -60,7 +61,7 @@ public class SurfaceSpline implements Brush { tipy = editSession.getNearestSurfaceTerrainBlock(tipx, tipz, tipy, 0, maxY); if (tipy == -1) continue; if (radius == 0) { - BlockVector3 set = MutableBlockVector3.get(tipx, tipy, tipz); + BlockVector3 set = mutable.setComponents(tipx, tipy, tipz); try { pattern.apply(editSession, set, set); } catch (WorldEditException e) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/VirtualWorld.java b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/VirtualWorld.java index 4eb958fcb..4a2009b58 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/VirtualWorld.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/VirtualWorld.java @@ -24,7 +24,12 @@ public interface VirtualWorld extends SimpleWorld, FaweQueue, Closeable { @Override default BaseBlock getFullBlock(BlockVector3 position) { - return getLazyBlock(position).toBaseBlock(); + return getBlock(position).toBaseBlock(); + } + + @Override + default BaseBlock getFullBlock(int x, int y, int z) { + return getBlock(x, y, z).toBaseBlock(); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualExtent.java index c8b29f3ef..4dc128a32 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/VisualExtent.java @@ -1,14 +1,12 @@ package com.boydti.fawe.object.brush.visualization; -import com.boydti.fawe.FaweCache; import com.boydti.fawe.example.IntFaweChunk; import com.boydti.fawe.example.NullQueueIntFaweChunk; import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.FaweQueue; -import com.boydti.fawe.object.visitor.FaweChunkVisitor; import com.boydti.fawe.util.MathMan; + import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector2; @@ -17,7 +15,6 @@ import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockStateHolder; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectIterator; public class VisualExtent extends AbstractDelegateExtent { @@ -40,7 +37,7 @@ public class VisualExtent extends AbstractDelegateExtent { @Override public boolean setBlock(int x, int y, int z, BlockStateHolder block) throws WorldEditException { - BlockStateHolder previous = super.getLazyBlock(x, y, z); + BlockStateHolder previous = super.getBlock(x, y, z); int cx = x >> 4; int cz = z >> 4; long chunkPair = MathMan.pairInt(cx, cz); @@ -67,9 +64,7 @@ public class VisualExtent extends AbstractDelegateExtent { } public void clear(VisualExtent other, FawePlayer... players) { - ObjectIterator> iter = chunks.long2ObjectEntrySet().iterator(); - while (iter.hasNext()) { - Long2ObjectMap.Entry entry = iter.next(); + for (Long2ObjectMap.Entry entry : chunks.long2ObjectEntrySet()) { long pair = entry.getLongKey(); int cx = MathMan.unpairIntX(pair); int cz = MathMan.unpairIntY(pair); @@ -79,21 +74,15 @@ public class VisualExtent extends AbstractDelegateExtent { final int bx = cx << 4; final int bz = cz << 4; if (otherChunk == null) { - chunk.forEachQueuedBlock(new FaweChunkVisitor() { - @Override - public void run(int localX, int y, int localZ, int combined) { - combined = queue.getCombinedId4Data(bx + localX, y, bz + localZ, 0); - newChunk.setBlock(localX, y, localZ, combined); - } + chunk.forEachQueuedBlock((localX, y, localZ, combined) -> { + combined = queue.getCombinedId4Data(bx + localX, y, bz + localZ, 0); + newChunk.setBlock(localX, y, localZ, combined); }); } else { - chunk.forEachQueuedBlock(new FaweChunkVisitor() { - @Override - public void run(int localX, int y, int localZ, int combined) { - if (combined != otherChunk.getBlockCombinedId(localX, y, localZ)) { - combined = queue.getCombinedId4Data(bx + localX, y, bz + localZ, 0); - newChunk.setBlock(localX, y, localZ, combined); - } + chunk.forEachQueuedBlock((localX, y, localZ, combined) -> { + if (combined != otherChunk.getBlockCombinedId(localX, y, localZ)) { + combined = queue.getCombinedId4Data(bx + localX, y, bz + localZ, 0); + newChunk.setBlock(localX, y, localZ, combined); } }); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/changeset/BlockBagChangeSet.java b/worldedit-core/src/main/java/com/boydti/fawe/object/changeset/BlockBagChangeSet.java index 4e742229b..dbda97050 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/changeset/BlockBagChangeSet.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/changeset/BlockBagChangeSet.java @@ -1,6 +1,5 @@ package com.boydti.fawe.object.changeset; -import com.boydti.fawe.FaweCache; import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.util.ReflectionUtils; import com.sk89q.jnbt.CompoundTag; @@ -10,7 +9,6 @@ import com.sk89q.worldedit.extent.inventory.BlockBagException; import com.sk89q.worldedit.extent.inventory.UnplaceableBlockException; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; @@ -89,10 +87,10 @@ public class BlockBagChangeSet extends AbstractDelegateChangeSet { try { blockBag.fetchPlacedBlock(typeTo.getDefaultState()); } catch (UnplaceableBlockException e) { - throw new FaweException.FaweBlockBagException(); + throw FaweException.BLOCK_BAG; } catch (BlockBagException e) { missingBlocks[typeTo.getInternalId()]++; - throw new FaweException.FaweBlockBagException(); + throw FaweException.BLOCK_BAG; } } if (mine) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/AbstractDelegateFaweClipboard.java b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/AbstractDelegateFaweClipboard.java index f41a37790..37c9de4dd 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/AbstractDelegateFaweClipboard.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/AbstractDelegateFaweClipboard.java @@ -1,15 +1,14 @@ package com.boydti.fawe.object.clipboard; import com.boydti.fawe.jnbt.NBTStreamer; + import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; import java.util.List; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/CPUOptimizedClipboard.java b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/CPUOptimizedClipboard.java index a012b5358..6544286a6 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/CPUOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/CPUOptimizedClipboard.java @@ -1,21 +1,18 @@ package com.boydti.fawe.object.clipboard; -import com.boydti.fawe.FaweCache; import com.boydti.fawe.jnbt.NBTStreamer; import com.boydti.fawe.object.IntegerTrio; import com.boydti.fawe.util.ReflectionUtils; + import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.IntTag; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; @@ -239,9 +236,9 @@ public class CPUOptimizedClipboard extends FaweClipboard { @Override public > boolean setBlock(int index, B block) { states[index] = block.getInternalId(); - boolean hasNbt = block instanceof BaseBlock && ((BaseBlock)block).hasNbtData(); + boolean hasNbt = block instanceof BaseBlock && block.hasNbtData(); if (hasNbt) { - setTile(index, ((BaseBlock)block).getNbtData()); + setTile(index, block.getNbtData()); } return true; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/EmptyClipboard.java b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/EmptyClipboard.java index 0254fe2e2..78d49acca 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/EmptyClipboard.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/EmptyClipboard.java @@ -78,7 +78,7 @@ public class EmptyClipboard implements Clipboard { } @Override - public BlockState getLazyBlock(BlockVector3 position) { + public BlockState getBlock(BlockVector3 position) { return BlockTypes.AIR.getDefaultState(); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/FaweClipboard.java b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/FaweClipboard.java index d7f9534e8..5b7199ae4 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/FaweClipboard.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/FaweClipboard.java @@ -2,27 +2,24 @@ package com.boydti.fawe.object.clipboard; import com.boydti.fawe.jnbt.NBTStreamer; import com.boydti.fawe.util.ReflectionUtils; + +import static com.google.common.base.Preconditions.checkNotNull; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.IntTag; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; import java.util.Map; -import javax.annotation.Nullable; - - -import static com.google.common.base.Preconditions.checkNotNull; public abstract class FaweClipboard { public abstract BaseBlock getBlock(int x, int y, int z); @@ -66,8 +63,8 @@ public abstract class FaweClipboard { */ public abstract void forEach(BlockReader task, boolean air); - public static abstract class BlockReader { - public abstract > void run(int x, int y, int z, B block); + public interface BlockReader { + > void run(int x, int y, int z, B block); } public abstract void streamBiomes(final NBTStreamer.ByteReader task); @@ -86,7 +83,6 @@ public abstract class FaweClipboard { public List getTileEntities() { final List tiles = new ArrayList<>(); forEach(new BlockReader() { - private int index = 0; @Override public > void run(int x, int y, int z, B block) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/OffsetFaweClipboard.java b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/OffsetFaweClipboard.java index a09026fb4..3982df681 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/OffsetFaweClipboard.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/OffsetFaweClipboard.java @@ -3,7 +3,6 @@ package com.boydti.fawe.object.clipboard; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; public class OffsetFaweClipboard extends AbstractDelegateFaweClipboard { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/ReadOnlyClipboard.java b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/ReadOnlyClipboard.java index 8ffc068cf..f767c4ed9 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/ReadOnlyClipboard.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/ReadOnlyClipboard.java @@ -1,17 +1,15 @@ package com.boydti.fawe.object.clipboard; import com.boydti.fawe.jnbt.NBTStreamer; + import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; import java.util.List; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/WorldCopyClipboard.java b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/WorldCopyClipboard.java index c998dce2d..dc3818b84 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/WorldCopyClipboard.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/WorldCopyClipboard.java @@ -79,22 +79,19 @@ public class WorldCopyClipboard extends ReadOnlyClipboard { if (region instanceof CuboidRegion) { if (air) { ((CuboidRegion) region).setUseOldIterator(true); - RegionVisitor visitor = new RegionVisitor(region, new RegionFunction() { - @Override - public boolean apply(BlockVector3 pos) throws WorldEditException { - BaseBlock block = getBlockAbs(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); - int x = pos.getBlockX() - mx; - int y = pos.getBlockY() - my; - int z = pos.getBlockZ() - mz; - if (block.hasNbtData()) { - Map values = ReflectionUtils.getMap(block.getNbtData().getValue()); - values.put("x", new IntTag(x)); - values.put("y", new IntTag(y)); - values.put("z", new IntTag(z)); - } - task.run(x, y, z, block); - return true; + RegionVisitor visitor = new RegionVisitor(region, pos1 -> { + BaseBlock block = getBlockAbs(pos1.getBlockX(), pos1.getBlockY(), pos1.getBlockZ()); + int x = pos1.getBlockX() - mx; + int y = pos1.getBlockY() - my; + int z = pos1.getBlockZ() - mz; + if (block.hasNbtData()) { + Map values = ReflectionUtils.getMap(block.getNbtData().getValue()); + values.put("x", new IntTag(x)); + values.put("y", new IntTag(y)); + values.put("z", new IntTag(z)); } + task.run(x, y, z, block); + return true; }, extent instanceof EditSession ? (EditSession) extent : null); Operations.completeBlindly(visitor); } else { @@ -107,7 +104,6 @@ public class WorldCopyClipboard extends ReadOnlyClipboard { int y = pos.getBlockY() - my; int z = pos.getBlockZ() - mz; if (region.contains(pos)) { -// BlockState block = getBlockAbs(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); BaseBlock block = extent.getFullBlock(pos); if (block.hasNbtData()) { Map values = ReflectionUtils.getMap(block.getNbtData().getValue()); @@ -118,9 +114,8 @@ public class WorldCopyClipboard extends ReadOnlyClipboard { if (!block.getBlockType().getMaterial().isAir()) { task.run(x, y, z, block); } - } else { -// task.run(x, y, z, EditSession.nullBlock); } + return true; } }, extent instanceof EditSession ? (EditSession) extent : null); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/WorldCutClipboard.java b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/WorldCutClipboard.java index 73d1fa467..c8512e8e8 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/WorldCutClipboard.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/WorldCutClipboard.java @@ -25,6 +25,7 @@ public class WorldCutClipboard extends WorldCopyClipboard { return block; } + @Override public BaseBlock getBlockAbs(int x, int y, int z) { BaseBlock block = extent.getFullBlock(BlockVector3.at(x, y, z)); extent.setBlock(x, y, z, BlockTypes.AIR.getDefaultState()); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/remap/RemappedClipboard.java b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/remap/RemappedClipboard.java deleted file mode 100644 index 3f6fb01ab..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/remap/RemappedClipboard.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.boydti.fawe.object.clipboard.remap; - -import com.boydti.fawe.jnbt.NBTStreamer; -import com.boydti.fawe.object.clipboard.AbstractDelegateFaweClipboard; -import com.boydti.fawe.object.clipboard.FaweClipboard; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; - -// TODO FIXME -public class RemappedClipboard extends AbstractDelegateFaweClipboard { - private final ClipboardRemapper remapper; - - public RemappedClipboard(FaweClipboard parent, ClipboardRemapper remapper) { - super(parent); - this.remapper = remapper; - } - - @Override - public BaseBlock getBlock(int x, int y, int z) { - return remapper.remap(super.getBlock(x, y, z)); - } - - @Override - public BaseBlock getBlock(int index) { - return remapper.remap(super.getBlock(index)); - } - - @Override - public void forEach(BlockReader task, boolean air) { - super.forEach(new BlockReader() { - @Override - public > void run(int x, int y, int z, B block) { - task.run(x, y, z, remapper.remap(block)); - } - }, air); - } - - @Override - public void streamCombinedIds(NBTStreamer.ByteReader task) { - super.streamCombinedIds(task); - } -// -// @Override -// public void streamIds(NBTStreamer.ByteReader task) { -// super.streamIds(new NBTStreamer.ByteReader() { -// @Override -// public void run(int index, int byteValue) { -// if (remapper.hasRemapId(byteValue)) { -// int result = remapper.remapId(byteValue); -// if (result != byteValue) { -// task.run(index, result); -// } else { -// task.run(index, getBlock(index).getId()); -// } -// } -// } -// }); -// } -// -// @Override -// public void streamDatas(NBTStreamer.ByteReader task) { -// super.streamDatas(new NBTStreamer.ByteReader() { -// @Override -// public void run(int index, int byteValue) { -// if (remapper.hasRemapData(byteValue)) { -// task.run(index, getBlock(index).getData()); -// } -// } -// }); -// } -} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/remap/WikiScraper.java b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/remap/WikiScraper.java index c495ef909..80ef67d78 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/remap/WikiScraper.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/remap/WikiScraper.java @@ -2,14 +2,18 @@ package com.boydti.fawe.object.clipboard.remap; import com.boydti.fawe.util.MainUtil; + import com.google.common.io.Resources; import com.google.common.reflect.TypeToken; import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; + import java.io.File; import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.StandardOpenOption; +import java.util.EnumMap; import java.util.HashMap; import java.util.Map; @@ -23,7 +27,7 @@ public class WikiScraper { Wiki(String url) {this.url = url;} } - private Map> cache = new HashMap<>(); + private EnumMap> cache = new EnumMap<>(WikiScraper.Wiki.class); public Map expand(Map map) { HashMap newMap = new HashMap<>(map); @@ -50,8 +54,8 @@ public class WikiScraper { String str = Resources.toString(file.toURL(), Charset.defaultCharset()); return gson.fromJson(str, new TypeToken>() { }.getType()); - } catch (Throwable ignore) { - ignore.printStackTrace(); + } catch (JsonSyntaxException | IOException e) { + e.printStackTrace(); } } map = scrape(wiki); @@ -94,15 +98,15 @@ public class WikiScraper { return map; } else { String header = wiki == Wiki.ITEM_MAPPINGS_PE ? "=== Item IDs ===" : "{{"; - String footer = "{{-}}"; - String prefix = "{{id table|"; int headerIndex = text.indexOf(header); if (headerIndex == -1) return map; + String footer = "{{-}}"; int endIndex = text.indexOf(footer, headerIndex); String part = text.substring(headerIndex, endIndex == -1 ? text.length() : endIndex); int id = 255; + String prefix = "{{id table|"; for (String line : part.split("\n")) { String lower = line.toLowerCase(); if (lower.startsWith(prefix)) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/AdaptedSetCollection.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/AdaptedSetCollection.java new file mode 100644 index 000000000..0f0b33b7b --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/AdaptedSetCollection.java @@ -0,0 +1,135 @@ +package com.boydti.fawe.object.collection; + +import com.google.common.base.Function; +import com.google.common.collect.Collections2; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; +import java.util.Spliterator; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.stream.Stream; + +/** + * Adapt a collection to a set + * (It's assumed that the collection is set like, otherwise behavior will be weird) + * + * @param + */ +public class AdaptedSetCollection implements Set { + private final Function adapter; + private final Collection adapted; + private final Collection original; + + public AdaptedSetCollection(Collection collection, Function adapter) { + this.original = collection; + this.adapted = Collections2.transform(collection, adapter); + this.adapter = adapter; + } + + public Collection getOriginal() { + return original; + } + + @Override + public int size() { + return adapted.size(); + } + + @Override + public boolean isEmpty() { + return adapted.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return adapted.contains(o); + } + + @NotNull + @Override + public Iterator iterator() { + return adapted.iterator(); + } + + @NotNull + @Override + public Object[] toArray() { + return adapted.toArray(); + } + + @NotNull + @Override + public V[] toArray(@NotNull V[] a) { + return adapted.toArray(a); + } + + public boolean add(V v) { + return adapted.add(v); + } + + @Override + public boolean remove(Object o) { + return adapted.remove(o); + } + + @Override + public boolean containsAll(@NotNull Collection c) { + return adapted.containsAll(c); + } + + public boolean addAll(@NotNull Collection c) { + return adapted.addAll(c); + } + + @Override + public boolean removeAll(@NotNull Collection c) { + return adapted.removeAll(c); + } + + public boolean removeIf(Predicate filter) { + return adapted.removeIf(filter); + } + + @Override + public boolean retainAll(@NotNull Collection c) { + return adapted.retainAll(c); + } + + @Override + public void clear() { + adapted.clear(); + } + + @Override + public boolean equals(Object o) { + return adapted.equals(o); + } + + @Override + public int hashCode() { + return adapted.hashCode(); + } + + @Override + public Spliterator spliterator() { + return adapted.spliterator(); + } + + @Override + public Stream stream() { + return adapted.stream(); + } + + @Override + public Stream parallelStream() { + return adapted.parallelStream(); + } + + public void forEach(Consumer action) { + adapted.forEach(action); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/BlockSet.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/BlockSet.java new file mode 100644 index 000000000..a96a8f340 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/BlockSet.java @@ -0,0 +1,112 @@ +package com.boydti.fawe.object.collection; + +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.AbstractRegion; +import com.sk89q.worldedit.regions.RegionOperationException; +import com.sk89q.worldedit.world.World; + +import java.util.AbstractSet; +import java.util.Iterator; +import java.util.Set; + +public abstract class BlockSet extends AbstractRegion { + private final int chunkOffsetX; + private final int chunkOffsetZ; + private final int blockOffsetX; + private final int blockOffsetZ; + + public BlockSet(int offsetX, int offsetZ) { + super(null); + this.chunkOffsetX = offsetX; + this.chunkOffsetZ = offsetZ; + this.blockOffsetX = offsetX << 4; + this.blockOffsetZ = offsetZ << 4; + } + + @Override + public boolean contains(Object o) { + try { + return contains((BlockVector3) o); + } catch (ClassCastException e) { + e.printStackTrace(); + return false; + } + } + + public boolean contains(BlockVector3 obj) { + return contains(obj.getX(), obj.getY(), obj.getZ()); + } + + protected final int lowestBit(long bitBuffer) { + final long lowBit = Long.lowestOneBit(bitBuffer); + return Long.bitCount(lowBit - 1); + } + + protected final int highestBit(long bitBuffer) { + final long lowBit = Long.highestOneBit(bitBuffer); + return Long.bitCount(lowBit - 1); + } + + @Override + public boolean isGlobal() { + return false; + } + + public final int getBlockOffsetX() { + return blockOffsetX; + } + + public int getBlockOffsetZ() { + return blockOffsetZ; + } + + public int getChunkOffsetX() { + return chunkOffsetX; + } + + public int getChunkOffsetZ() { + return chunkOffsetZ; + } + + @Override + public boolean add(BlockVector3 p) { + return add(p.getX(), p.getY(), p.getZ()); + } + + public boolean remove(BlockVector3 p) { + return remove(p.getX(), p.getY(), p.getZ()); + } + + @Override + public boolean remove(Object o) { + try { + return remove((BlockVector3) o); + } catch (ClassCastException e) { + e.printStackTrace(); + return false; + } + } + + @Override + public abstract boolean contains(int x, int y, int z); + public abstract boolean add(int x, int y, int z); + public abstract void set(int x, int y, int z); + public abstract void clear(int x, int y, int z); + public abstract boolean remove(int x, int y, int z); + public abstract Iterator iterator(); + public abstract Set getChunks(); + public abstract Set getChunkCubes(); + public abstract BlockVector3 getMaximumPoint(); + public abstract BlockVector3 getMinimumPoint(); + + @Override + public void expand(BlockVector3... changes) throws RegionOperationException { + + } + + @Override + public void contract(BlockVector3... changes) throws RegionOperationException { + + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/BlockVectorSet.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/BlockVectorSet.java index b406d553c..681c13636 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/BlockVectorSet.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/BlockVectorSet.java @@ -38,13 +38,15 @@ public class BlockVectorSet extends AbstractCollection implements int newSize = count + size; if (newSize > index) { int localIndex = index - count; - BlockVector3 pos = mutable.setComponents(set.getIndex(localIndex)); - int pair = entry.getIntKey(); - int cx = MathMan.unpairX(pair); - int cz = MathMan.unpairY(pair); - pos = pos.mutX((cx << 11) + pos.getBlockX()); - pos = pos.mutZ((cz << 11) + pos.getBlockZ()); - return pos; + BlockVector3 pos = set.getIndex(localIndex); + if (pos != null) { + int pair = entry.getIntKey(); + int cx = MathMan.unpairX(pair); + int cz = MathMan.unpairY(pair); + pos = pos.mutX((cx << 11) + pos.getBlockX()); + pos = pos.mutZ((cz << 11) + pos.getBlockZ()); + return pos; + } } count += newSize; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/CpuBlockSet.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/CpuBlockSet.java new file mode 100644 index 000000000..974e16e53 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/CpuBlockSet.java @@ -0,0 +1,137 @@ +//package com.boydti.fawe.object.collection; +// +//import com.sk89q.worldedit.math.BlockVector2; +//import com.sk89q.worldedit.math.BlockVector3; +// +//import java.util.Iterator; +//import java.util.Set; +// +//public final class CpuBlockSet extends BlockSet { +// private static final int DIRTY_SET = 0x1; +// private static final int DIRTY_CLEAR = 0x10; +// +// public static int WORLD_HEIGHT = 256; +// private final long[] bits; +// private final byte[] dirty; +// private final int chunkShift; +// private final int chunkShift2; +// +// public CpuBlockSet(int size, int offsetX, int offsetZ) { +// super(offsetX, offsetZ); +// size = size == 1 ? 1 : Integer.highestOneBit(size - 1) * 2; +// int arrayLen = (size * size * WORLD_HEIGHT) >> 6; +// int bitShift = Integer.bitCount(Integer.highestOneBit(size) - 1); +// this.chunkShift = 12 + bitShift; +// this.chunkShift2 = 12 + bitShift * 2; +// this.bits = new long[arrayLen]; +// this.dirty = new byte[arrayLen >> 12]; +// } +// +// @Override +// public BlockVector3 getMinimumPoint() { +// +// } +// +// @Override +// public BlockVector3 getMaximumPoint() { +// // visited set +// // queue (longs) +// } +// +// @Override +// public Iterator iterator() { +// +// } +// +// @Override +// public Set getChunks() { +// // next 65536 +// } +// +// @Override +// public Set getChunkCubes() { +// // next 4096 +// } +// +// private final boolean contains(final int i) { +// return (bits[i >> 6] & (1L << (i & 0x3F))) != 0; +// } +// +// private final boolean add(final int i) { +// int offset = i >> 6; +// long value = bits[offset]; +// long mask = (1L << (i & 0x3F)); +// if ((value & mask) == 0) { +// dirty[i >> 16] |= DIRTY_SET; +// bits[offset] = value | mask; +// return true; +// } +// return false; +// } +// +// private final boolean remove(final int i) { +// int offset = i >> 6; +// long value = bits[offset]; +// long mask = (1L << (i & 0x3F)); +// if ((value & mask) != 0) { +// bits[offset] = value & ~mask; +// dirty[i >> 16] |= DIRTY_CLEAR; +// return true; +// } +// return false; +// } +// +// private final void set(final int i) { +// bits[i >> 6] |= (1L << (i & 0x3F)); +// dirty[i >> 12] |= DIRTY_SET; +// } +// +// private final void clear(final int i) { +// bits[i >> 6] &= ~(1L << (i & 0x3F)); +// dirty[i >> 12] |= DIRTY_CLEAR; +// } +// +// @Override +// public boolean contains(int x, int y, int z) { +// return contains(index(x, y, z)); +// } +// +// @Override +// public boolean add(int x, int y, int z) { +// return add(index(x, y, z)); +// } +// +// @Override +// public void set(int x, int y, int z) { +// set(index(x, y, z)); +// } +// +// @Override +// public void clear(int x, int y, int z) { +// clear(index(x, y, z)); +// } +// +// @Override +// public boolean remove(int x, int y, int z) { +// return remove(index(x, y, z)); +// } +// +// @Override +// public void clear() { +// for (int i = 0; i < dirty.length; i++) { +// boolean isDirty = dirty[i] != 0; +// if (isDirty) { +// dirty[i] = 0; +// int start = i << 10; +// int end = Math.min(bits.length, (i + 1) << 10); +// for (int j = start; j < end; j++) { +// bits[j] = 0; +// } +// } +// } +// } +// +// private final int index(int x, int y, int z) { +// return (((y & 15) << 8) | ((z & 15) << 4) | (x & 15)) | ((y >> 4) << chunkShift2) | ((z >> 4) << chunkShift) | ((x >> 4) << 12); +// } +//} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/DifferentialArray.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/DifferentialArray.java index a8c399721..9141e7d6d 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/DifferentialArray.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/DifferentialArray.java @@ -244,9 +244,9 @@ public final class DifferentialArray implements DifferentialCollection { return dataBytes; } -// public char[] getCharArray() { -// return dataChars; -// } + public char[] getCharArray() { + return dataChars; + } public int[] getIntArray() { return dataInts; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/DifferentialCharBlockBuffer.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/DifferentialCharBlockBuffer.java new file mode 100644 index 000000000..15a52d950 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/DifferentialCharBlockBuffer.java @@ -0,0 +1,213 @@ +package com.boydti.fawe.object.collection; + +import com.boydti.fawe.object.FaweInputStream; +import com.boydti.fawe.object.FaweOutputStream; + +import java.io.IOException; +import java.lang.reflect.Array; + +/** + * Records changes made through the {@link #set(int, int, int, char)} method
+ * Changes are not recorded if you edit the raw data + */ +public final class DifferentialCharBlockBuffer implements DifferentialCollection { + + private final int width, length; + private final int t1, t2; + private char[][][][][] data; + private char[][][][][] changes; + + public DifferentialCharBlockBuffer(int width, int length) { + this.width = width; + this.length = length; + this.t1 = (length + 15) >> 4; + this.t2 = (width + 15) >> 4; + } + + @Override + public char[][][][][] get() { + return data; + } + + @Override + public void flushChanges(FaweOutputStream out) throws IOException { + boolean modified = isModified(); + out.writeBoolean(modified); + + if (modified) { + writeArray(changes, 0, 0, out); + } + clearChanges(); + } + + private void writeArray(Object arr, int level, int index, FaweOutputStream out) throws IOException { + if (level == 4) { + if (arr != null) { + char[] level4 = (char[]) arr; + out.writeVarInt(level4.length); + for (char c : level4) { + out.writeChar(c); + } + } else { + out.writeVarInt(0); + } + } else { + int len = arr == null ? 0 : Array.getLength(arr); + out.writeVarInt(len); + for (int i = 0; i < len; i++) { + Object elem = Array.get(arr, i); + writeArray(elem, level + 1, i, out); + } + } + } + + @Override + public void undoChanges(FaweInputStream in) throws IOException { + if (changes != null && changes.length != 0) throw new IllegalStateException("There are uncommitted changes, please flush first"); + boolean modified = in.readBoolean(); + if (modified) { + int len = in.readVarInt(); + if (len == 0) { + data = null; + } else { + for (int i = 0; i < len; i++) { + readArray(data, i, 1, in); + } + } + } + + clearChanges(); + } + + @Override + public void redoChanges(FaweInputStream in) throws IOException { + clearChanges(); + throw new UnsupportedOperationException("Not implemented"); + } + + private void readArray(Object dataElem, int index, int level, FaweInputStream in) throws IOException { + int len = in.readVarInt(); + if (level == 4) { + char[][] castedElem = (char[][]) dataElem; + if (len == 0) { + castedElem[index] = null; + } else { + char[] current = castedElem[index]; + for (int i = 0; i < len; i++) { + current[i] = in.readChar(); + } + } + } else { + if (len == 0) { + Array.set(dataElem, index, null); + } else { + Object nextElem = Array.get(dataElem, index); + for (int i = 0; i < len; i++) { + readArray(nextElem, i, level + 1, in); + } + } + } + } + + public boolean isModified() { + return changes != null; + } + + public void clearChanges() { + changes = null; + } + + public void set(int x, int y, int z, char combined) { + if (combined == 0) combined = 1; + int localX = x & 15; + int localZ = z & 15; + int chunkX = x >> 4; + int chunkZ = z >> 4; + if (data == null) { + data = new char[t1][][][][]; + changes = new char[0][][][][]; + } + + char[][][][] arr = data[chunkZ]; + if (arr == null) { + arr = data[chunkZ] = new char[t2][][][]; + } + char[][][] arr2 = arr[chunkX]; + if (arr2 == null) { + arr2 = arr[chunkX] = new char[256][][]; + } + + char[][] yMap = arr2[y]; + if (yMap == null) { + arr2[y] = yMap = new char[16][]; + } + boolean newSection; + char current; + char[] zMap = yMap[localZ]; + if (zMap == null) { + yMap[localZ] = zMap = new char[16]; + + if (changes == null) { + changes = new char[t1][][][][]; + } else if (changes != null && changes.length != 0) { + initialChange(changes, chunkX, chunkZ, localX, localZ, y, (char) -combined); + } + + } else { + if (changes == null || changes.length == 0) changes = new char[t1][][][][]; + appendChange(changes, chunkX, chunkZ, localX, localZ, y, (char) (zMap[localX] - combined)); + } + + zMap[localX] = combined; + } + + private void initialChange(char[][][][][] src, int chunkX, int chunkZ, int localX, int localZ, int y, char combined) { + char[][][][] arr = src[chunkZ]; + if (arr == null) { + src[chunkZ] = new char[0][][][]; + return; + } else if (arr.length == 0) return; + + char[][][] arr2 = arr[chunkX]; + if (arr2 == null) { + arr[chunkX] = new char[0][][]; + return; + } else if (arr2.length == 0) return; + + char[][] yMap = arr2[y]; + if (yMap == null) { + arr2[y] = new char[0][]; + return; + } else if (yMap.length == 0) return; + + char[] zMap = yMap[localZ]; + if (zMap == null) { + yMap[localZ] = new char[0]; + return; + } else if (zMap.length == 0) return; + + char current = zMap[localX]; + zMap[localX] = combined; + } + + private void appendChange(char[][][][][] src, int chunkX, int chunkZ, int localX, int localZ, int y, char combined) { + char[][][][] arr = src[chunkZ]; + if (arr == null || arr.length == 0) { + arr = src[chunkZ] = new char[t2][][][]; + } + char[][][] arr2 = arr[chunkX]; + if (arr2 == null || arr2.length == 0) { + arr2 = arr[chunkX] = new char[256][][]; + } + + char[][] yMap = arr2[y]; + if (yMap == null || yMap.length == 0) { + arr2[y] = yMap = new char[16][]; + } + char[] zMap = yMap[localZ]; + if (zMap == null || zMap.length == 0) { + yMap[localZ] = zMap = new char[16]; + } + zMap[localX] = combined; + } +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/FastRandomCollection.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/FastRandomCollection.java index d82de44da..3ca33a53a 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/FastRandomCollection.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/FastRandomCollection.java @@ -12,7 +12,7 @@ public class FastRandomCollection extends RandomCollection { super(weights, random); int max = 0; int[] counts = new int[weights.size()]; - Double[] weightDoubles = weights.values().toArray(new Double[weights.size()]); + Double[] weightDoubles = weights.values().toArray(new Double[0]); for (int i = 0; i < weightDoubles.length; i++) { int weight = (int) (weightDoubles[i] * 100); counts[i] = weight; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/IterableThreadLocal.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/IterableThreadLocal.java index c31704c8d..2aef7daf7 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/IterableThreadLocal.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/IterableThreadLocal.java @@ -11,8 +11,7 @@ import java.util.Iterator; import java.util.concurrent.ConcurrentLinkedDeque; public abstract class IterableThreadLocal extends ThreadLocal implements Iterable { - private ThreadLocal flag; - private ConcurrentLinkedDeque allValues = new ConcurrentLinkedDeque<>(); + private final ConcurrentLinkedDeque allValues = new ConcurrentLinkedDeque<>(); public IterableThreadLocal() { } @@ -21,7 +20,9 @@ public abstract class IterableThreadLocal extends ThreadLocal implements I protected final T initialValue() { T value = init(); if (value != null) { - allValues.add(value); + synchronized (this) { + allValues.add(value); + } } return value; } @@ -36,7 +37,12 @@ public abstract class IterableThreadLocal extends ThreadLocal implements I } public void clean() { - IterableThreadLocal.clean(this); + if (!allValues.isEmpty()) { + synchronized (this) { + IterableThreadLocal.clean(this); + allValues.clear(); + } + } } public static void clean(ThreadLocal instance) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/LocalBlockVector2DSet.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/LocalBlockVector2DSet.java index 47b2f9749..f51d935c7 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/LocalBlockVector2DSet.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/LocalBlockVector2DSet.java @@ -3,6 +3,7 @@ package com.boydti.fawe.object.collection; import com.boydti.fawe.util.MathMan; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.MutableBlockVector2; +import org.jetbrains.annotations.NotNull; import java.util.Collection; import java.util.Iterator; @@ -209,25 +210,16 @@ public class LocalBlockVector2DSet implements Set { @Override public boolean containsAll(Collection c) { - for (Object o : c) { - if (!contains(o)) { - return false; - } - } - return true; + return c.stream().allMatch(this::contains); } @Override public boolean addAll(Collection c) { - boolean result = false; - for (BlockVector2 v : c) { - result |= add(v); - } - return result; + return c.stream().map(this::add).reduce(false, (a, b) -> a || b); } @Override - public boolean retainAll(Collection c) { + public boolean retainAll(@NotNull Collection c) { boolean result = false; int size = size(); int index = -1; @@ -246,27 +238,7 @@ public class LocalBlockVector2DSet implements Set { @Override public boolean removeAll(Collection c) { - boolean result = false; - for (Object o : c) { - result |= remove(o); - } - return result; - } - - public void forEach(BlockVector2DSetVisitor visitor) { - int size = size(); - int index = -1; - for (int i = 0; i < size; i++) { - index = set.nextSetBit(index + 1); - int x = MathMan.unpairSearchCoordsX(index); - int y = MathMan.unpairSearchCoordsY(index); - mutable.setComponents(x, y); - visitor.run(x, y, index); - } - } - - public static abstract class BlockVector2DSetVisitor { - public abstract void run(int x, int y, int index); + return c.stream().map(this::remove).reduce(false, (a, b) -> a || b); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/LocalBlockVectorSet.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/LocalBlockVectorSet.java index e1c83573f..8faea1f83 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/LocalBlockVectorSet.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/LocalBlockVectorSet.java @@ -101,7 +101,7 @@ public class LocalBlockVectorSet implements Set { this.offsetZ = z; } - public BlockVector3 getIndex(int getIndex) { + protected BlockVector3 getIndex(int getIndex) { int size = size(); if (getIndex > size) { return null; @@ -322,8 +322,8 @@ public class LocalBlockVectorSet implements Set { } } - public static abstract class BlockVectorSetVisitor { - public abstract void run(int x, int y, int z, int index); + public interface BlockVectorSetVisitor { + void run(int x, int y, int z, int index); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/MemBlockSet.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/MemBlockSet.java new file mode 100644 index 000000000..a1b43639c --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/MemBlockSet.java @@ -0,0 +1,917 @@ +package com.boydti.fawe.object.collection; + +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.MutableBlockVector2; +import com.sk89q.worldedit.math.MutableBlockVector3; +import org.jetbrains.annotations.NotNull; + +import java.util.AbstractSet; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + * Memory optimized BlockVector3 Set using a sparsely populated bitset and grouped by chunk section + * Note on spaghetti code / duplication + * - Uses a minimum of 1 bit per entry + * - 99.9% of the time there are no if checks on get/clear + * - Grouping / iteration is by chunk section, and the y>z>x order + */ +public final class MemBlockSet extends BlockSet { + private final static int CHUNK_LAYERS = 16; + private final static int BITS_PER_LAYER = 4096; + private final static int BITS_PER_WORD = 6; + private final static int WORDS = BITS_PER_LAYER >> BITS_PER_WORD; + private final static IRow NULL_ROW_X = new NullRowX(); + private final static IRow NULL_ROW_Z = new NullRowZ(); + private final static IRow NULL_ROW_Y = new NullRowY(); + private final IRow[] rows; + private final MutableBlockVector3 mutable; + + public MemBlockSet() { + this(16, 0, 0); + } + + public MemBlockSet(int size, int offsetX, int offsetZ) { + super(offsetX, offsetZ); + this.rows = new IRow[size]; + for (int i = 0; i < size; i++) rows[i] = NULL_ROW_X; + this.mutable = new MutableBlockVector3(); + } + + @Override + public boolean contains(int x, int y, int z) { + x -= getBlockOffsetX(); + z -= getBlockOffsetZ(); + return rows[x >> 4].get(this.rows, x, y, z - getBlockOffsetZ()); + } + + @Override + public boolean add(int x, int y, int z) { + x -= getBlockOffsetX(); + z -= getBlockOffsetZ(); + return rows[x >> 4].add(this.rows, x, y, z - getBlockOffsetZ()); + } + + @Override + public void set(int x, int y, int z) { + x -= getBlockOffsetX(); + z -= getBlockOffsetZ(); + rows[x >> 4].set(this.rows, x, y, z - getBlockOffsetZ()); + } + + @Override + public void clear(int x, int y, int z) { + x -= getBlockOffsetX(); + z -= getBlockOffsetZ(); + rows[x >> 4].clear(this.rows, x, y, z - getBlockOffsetZ()); + } + + @Override + public boolean remove(int x, int y, int z) { + x -= getBlockOffsetX(); + z -= getBlockOffsetZ(); + return rows[x >> 4].remove(this.rows, x, y, z - getBlockOffsetZ()); + } + + public BlockVector3 getMinimumPoint() { + return BlockVector3.at(getMinX(), getMinY(), getMinZ()); + } + + public BlockVector3 getMaximumPoint() { + return BlockVector3.at(getMaxX(), getMaxY(), getMaxZ()); + } + + @Override + public Set getChunks() { + return new AbstractSet() { + @NotNull + @Override + public Iterator iterator() { + return new Iterator() { + private MutableBlockVector2 mutable = new MutableBlockVector2(); + private boolean hasNext; + private int X,Z; + private int setX, setZ; + + { + init(); + } + + private void init() { + for (;X < rows.length; X++) { + IRow nullRowX = rows[X]; + if (nullRowX instanceof RowX) { + RowX rowx = (RowX) nullRowX; + for (;Z < rowx.rows.length; Z++) { + IRow nullRowZ = rowx.rows[Z]; + if (nullRowZ instanceof RowZ) { + setX = X; + setZ = Z; + Z++; + hasNext = true; + return; + } + } + Z = 0; + } + } + hasNext = false; + } + + @Override + public boolean hasNext() { + return hasNext; + } + + @Override + public BlockVector2 next() { + mutable.setComponents(setX + getBlockOffsetX(), setZ + getBlockOffsetZ()); + init(); + return mutable; + } + + @Override + public void remove() { + throw new UnsupportedOperationException("This set is immutable."); + } + }; + } + + @Override + public int size() { + int size = 0; + for (int X = 0;X < rows.length; X++) { + IRow nullRowX = rows[X]; + if (nullRowX instanceof RowX) { + RowX rowx = (RowX) nullRowX; + for (int Z = 0; Z < rowx.rows.length; Z++) { + IRow nullRowZ = rowx.rows[Z]; + if (nullRowZ instanceof RowZ) { + size++; + } + } + } + } + return size; + } + + @Override + public boolean isEmpty() { + return MemBlockSet.this.isEmpty(); + } + + @Override + public boolean contains(Object o) { + if (o instanceof BlockVector2) { + BlockVector2 other = (BlockVector2) o; + IRow rowx = rows[other.getX() - getChunkOffsetX()]; + if (rowx instanceof RowX) { + return ((RowX) rowx).rows[other.getZ() - getChunkOffsetZ()] instanceof RowZ; + } + } + return false; + } + }; + } + + public Set getChunkCubes() { + return new AbstractSet() { + @Override + public Iterator iterator() { + return new Iterator() { + private MutableBlockVector3 mutable = new MutableBlockVector3(); + private boolean hasNext; + private int X, Z, Y; + private int setX, setY, setZ; + + { + init(); + } + + private void init() { + for (;X < rows.length; X++) { + IRow nullRowX = rows[X]; + if (nullRowX instanceof RowX) { + RowX rowx = (RowX) nullRowX; + for (;Z < rowx.rows.length; Z++) { + IRow nullRowZ = rowx.rows[Z]; + if (nullRowZ instanceof RowZ) { + RowZ rowz = (RowZ) nullRowZ; + for (;Y < rowz.rows.length;Y++) { + IRow nullRowY = rowz.rows[Y]; + if (nullRowY instanceof RowY) { + setX = X; + setY = Y; + setZ = Z; + Z++; + hasNext = true; + } + } + Y = 0; + } + } + Z = 0; + } + } + hasNext = false; + } + + @Override + public boolean hasNext() { + return hasNext; + } + + @Override + public BlockVector3 next() { + mutable.setComponents(setX + getBlockOffsetX(), setY, setZ + getBlockOffsetX()); + init(); + return mutable; + } + + @Override + public void remove() { + throw new UnsupportedOperationException("This set is immutable."); + } + }; + } + + @Override + public int size() { + int size = 0; + for (int X = 0;X < rows.length; X++) { + IRow nullRowX = rows[X]; + if (nullRowX instanceof RowX) { + RowX rowx = (RowX) nullRowX; + for (int Z = 0; Z < rowx.rows.length; Z++) { + IRow nullRowZ = rowx.rows[Z]; + if (nullRowZ instanceof RowZ) { + RowZ rowz = (RowZ) nullRowZ; + for (int Y = 0; Y < rowz.rows.length; Y++) { + IRow nullRowY = rowz.rows[Y]; + if (nullRowY instanceof RowY) { + size++; + } + } + } + } + } + } + return size; + } + + @Override + public boolean isEmpty() { + return MemBlockSet.this.isEmpty(); + } + + @Override + public boolean contains(Object o) { + if (o instanceof BlockVector3) { + BlockVector3 other = (BlockVector3) o; + IRow rowx = rows[other.getX() - getChunkOffsetX()]; + if (rowx instanceof RowX) { + IRow rowz = ((RowX) rowx).rows[other.getZ()]; + if (rowz instanceof RowZ) { + return ((RowZ) rowz).rows[other.getY() - getChunkOffsetZ()] instanceof RowY; + } + } + } + return false; + } + }; + } + + @Override + public int getMinY() { + int maxY = 15; + int maxy = 16; + int by = Integer.MAX_VALUE; + for (int X = 0; X < rows.length; X++) { + IRow nullRowX = rows[X]; + if (!(nullRowX instanceof RowX)) continue; + RowX rowx = (RowX) nullRowX; + for (int Z = 0; Z < rowx.rows.length; Z++) { + IRow nullRowZ = rowx.rows[Z]; + if (!(nullRowZ instanceof RowZ)) continue; + RowZ rowz = (RowZ) nullRowZ; + outer: + for (int Y = 0; Y <= maxY; Y++) { + IRow nullRowY = rowz.rows[Y]; + if (!(nullRowY instanceof RowY)) continue; + RowY rowY = (RowY) nullRowY; + int localMaxy = Y == maxY ? maxy : 15; + for (int y = 0, i = 0; y < localMaxy; y++) { + for (int xz = 0; xz < 4; xz++, i++) { + long val = rowY.bits[i]; + if (val != 0) { + if (y == 0) { + maxY = Y - 1; + maxy = 16; + } else { + maxY = Y; + maxy = y; + } + by = (Y << 4) + y; + if (by == 0) return 0; + break outer; + } + } + } + } + } + } + return by; + } + + @Override + public int getMaxY() { + int maxY = 0; + int maxy = 0; + int by = Integer.MIN_VALUE; + for (int X = 0; X < rows.length; X++) { + IRow nullRowX = rows[X]; + if (!(nullRowX instanceof RowX)) continue; + RowX rowx = (RowX) nullRowX; + for (int Z = 0; Z < rowx.rows.length; Z++) { + IRow nullRowZ = rowx.rows[Z]; + if (!(nullRowZ instanceof RowZ)) continue; + RowZ rowz = (RowZ) nullRowZ; + outer: + for (int Y = 15; Y >= maxY; Y--) { + IRow nullRowY = rowz.rows[Y]; + if (!(nullRowY instanceof RowY)) continue; + RowY rowY = (RowY) nullRowY; + int localMaxy = Y == maxY ? maxy : 0; + for (int y = 15, i = 63; y >= localMaxy; y--) { + for (int xz = 3; xz >= 0; xz--, i--) { + long val = rowY.bits[i]; + if (val != 0) { + if (y == 15) { + maxY = Y + 1; + maxy = 0; + } else { + maxY = Y; + maxy = y + 1; + } + by = (Y << 4) + y; + if (by == 255) return 255; + break outer; + } + } + } + } + } + } + return by; + } + + public int getMaxZ() { + int maxChunkZ = 0; + int maxz = -1; + int tz = Integer.MIN_VALUE; + for (int X = rows.length - 1; X >= 0; X--) { + IRow nullRowX = rows[X]; + if (!(nullRowX instanceof RowX)) continue; + RowX rowx = (RowX) nullRowX; + outer: + for (int Z = rowx.rows.length - 1; Z >= maxChunkZ ; Z--) { + IRow nullRowZ = rowx.rows[Z]; + if (!(nullRowZ instanceof RowZ)) continue; + RowZ rowz = (RowZ) nullRowZ; + if (Z != maxChunkZ) { + maxChunkZ = Z; + maxz = -1; + } + for (int Y = rowz.rows.length - 1; Y >= 0; Y--) { + IRow nullRowY = rowz.rows[Y]; + if (!(nullRowY instanceof RowY)) continue; + RowY rowY = (RowY) nullRowY; + for (int y = 15, i1 = 63; y >= 0; y--, i1 -= 4) { + for (int z = 12, i = i1; z > maxz - 3; z -= 4, i--) { + long bitBuffer = rowY.bits[i]; + if (bitBuffer != 0) { + int highest = highestBit(bitBuffer); + maxz = z + (highest >> 4); + if (maxz == 15) { + tz = (maxChunkZ << 4) + 15; + maxChunkZ++; + break outer; + } else { + tz = Math.max(tz, (maxChunkZ << 4) + maxz); + break; + } + } + } + } + } + break; + } + } + return tz + getBlockOffsetZ(); + } + + public int getMaxX() { + for (int X = rows.length - 1; X >= 0; X--) { + IRow nullRowX = rows[X]; + if (!(nullRowX instanceof RowX)) continue; + int tx = (X << 4); + RowX rowx = (RowX) nullRowX; + long or = 0; + for (int Z = rowx.rows.length - 1; Z >= 0 ; Z--) { + IRow nullRowZ = rowx.rows[Z]; + if (!(nullRowZ instanceof RowZ)) continue; + RowZ rowz = (RowZ) nullRowZ; + for (int Y = rowz.rows.length - 1; Y >= 0; Y--) { + IRow nullRowY = rowz.rows[Y]; + if (!(nullRowY instanceof RowY)) continue; + RowY rowY = (RowY) nullRowY; + for (long value : rowY.bits) { + or |= value; + } + or = (or & 0xFFFF) | ((or >> 16) & 0xFFFF) | ((or >> 32) & 0xFFFF) | ((or >> 48) & 0xFFFF); + if (highestBit(or) == 15) return tx + 15; + } + } + int highest = highestBit(or); + if (highest != 64) { + return tx + highest + getBlockOffsetX(); + } + } + return Integer.MAX_VALUE; + } + + public int getMinZ() { + int maxChunkZ = rows.length - 1; + int maxz = 16; + int bz = Integer.MAX_VALUE; + for (int X = 0; X < rows.length; X++) { + IRow nullRowX = rows[X]; + if (!(nullRowX instanceof RowX)) continue; + RowX rowx = (RowX) nullRowX; + outer: + for (int Z = 0; Z <= maxChunkZ; Z++) { + IRow nullRowZ = rowx.rows[Z]; + if (!(nullRowZ instanceof RowZ)) continue; + RowZ rowz = (RowZ) nullRowZ; + if (Z != maxChunkZ) { + maxChunkZ = Z; + maxz = 16; + } + for (int Y = 0; Y < rowz.rows.length; Y++) { + IRow nullRowY = rowz.rows[Y]; + if (!(nullRowY instanceof RowY)) continue; + RowY rowY = (RowY) nullRowY; + for (int y = 0, i1 = 0; y < 16; y++, i1 += 4) { + for (int z = 0, i = i1; z < maxz; z += 4, i++) { + long bitBuffer = rowY.bits[i]; + if (bitBuffer != 0) { + int lowest = lowestBit(bitBuffer); + maxz = z + (lowest >> 4); + if (maxz == 0) { + bz = (maxChunkZ << 4); + maxChunkZ--; + break outer; + } else { + bz = Math.min(bz, (maxChunkZ << 4) + maxz); + break; + } + } + } + } + } + break; + } + } + return bz + getBlockOffsetZ(); + } + + public int getMinX() { + for (int X = 0; X < rows.length; X++) { + IRow nullRowX = rows[X]; + if (!(nullRowX instanceof RowX)) continue; + int bx = X << 4; + RowX rowx = (RowX) nullRowX; + long or = 0; + for (int Z = 0; Z < rowx.rows.length; Z++) { + IRow nullRowZ = rowx.rows[Z]; + if (!(nullRowZ instanceof RowZ)) continue; + RowZ rowz = (RowZ) nullRowZ; + for (int Y = 0; Y < rowz.rows.length; Y++) { + IRow nullRowY = rowz.rows[Y]; + if (!(nullRowY instanceof RowY)) continue; + RowY rowY = (RowY) nullRowY; + for (long value : rowY.bits) { + or |= value; + } + or = (or & 0xFFFF) | ((or >> 16) & 0xFFFF) | ((or >> 32) & 0xFFFF) | ((or >> 48) & 0xFFFF); + if (lowestBit(or) == 0) return bx; + } + } + int lowest = lowestBit(or); + if (lowest != 64) { + return bx + lowest + getBlockOffsetX(); + } + } + return Integer.MAX_VALUE; + } + + public void iterate(BlockIterator iterator) { + for (int X = 0; X < rows.length; X++) { + IRow nullRowX = rows[X]; + if (!(nullRowX instanceof RowX)) continue; + int bx = getBlockOffsetX() + (X << 4); + RowX rowx = (RowX) nullRowX; + for (int Z = 0; Z < rowx.rows.length; Z++) { + IRow nullRowZ = rowx.rows[Z]; + if (!(nullRowZ instanceof RowZ)) continue; + int bz = getBlockOffsetZ() + (Z << 4); + RowZ rowz = (RowZ) nullRowZ; + for (int Y = 0; Y < rowz.rows.length; Y++) { + IRow nullRowY = rowz.rows[Y]; + if (!(nullRowY instanceof RowY)) continue; + int by = Y << 4; + RowY rowY = (RowY) nullRowY; + for (int y = 0, i = 0; y < 16; y++) { + for (int z = 0; z < 16; z += 4, i++) { + long bitBuffer = rowY.bits[i]; + if (bitBuffer != 0) { + if (bitBuffer == -1L) { + for (int zz = z; zz < z + 4; zz++) { + for (int x = 0; x < 16; x++) { + iterator.apply(bx + x, by + y, bz + zz); + } + } + continue; + } + do { + final long lowBit = Long.lowestOneBit(bitBuffer); + final int bitIndex = Long.bitCount(lowBit - 1); + int x = bitIndex & 15; + int zz = z + (bitIndex >> 4); + iterator.apply(bx + x, by + y, bz + zz); + bitBuffer = bitBuffer ^ lowBit; + } while (bitBuffer != 0); + } + + } + } + } + } + } + } + + @Override + public Iterator iterator() { + return new Iterator() { + private int bx, by, bz, zz, yy; + private RowX rowX; + private RowZ rowZ; + private RowY rowY; + private long[] bits; + private int bitsIndex = 0; + private int yIndex = 0; + private int zIndex = 0; + private int xIndex = 0; + private long bitBuffer = 0; + private boolean next; + + { + if (nextRowX()) { + if (nextRowZ()) { + if (nextRowY()) { + next = nextLong(); + } + } + } + } + + private boolean nextRowX() { + while (xIndex < rows.length) { + bx = getBlockOffsetX() + (xIndex << 4); + IRow nullRowX = rows[xIndex++]; + if (nullRowX instanceof RowX) { + rowX = (RowX) nullRowX; + return true; + } + } + return false; + } + + private boolean nextRowZ() { + while (zIndex < rowX.rows.length) { + bz = getBlockOffsetZ() + (zIndex << 4); + IRow nullRowZ = rowX.rows[zIndex++]; + if (nullRowZ instanceof RowZ) { + rowZ = (RowZ) nullRowZ; + return true; + } + } + if (nextRowX()) { + zIndex = 0; + return nextRowZ(); + } + return false; + } + + private boolean nextRowY() { + while (yIndex < rowZ.rows.length) { + by = yIndex << 4; + IRow nullRowY = rowZ.rows[yIndex++]; + if (nullRowY instanceof RowY) { + rowY = (RowY) nullRowY; + bits = rowY.bits; + return true; + } + } + if (nextRowZ()) { + yIndex = 0; + return nextRowY(); + } + return false; + } + + private boolean nextLong() { + if (bitBuffer == 0) { + do { + bitBuffer = bits[bitsIndex++]; + if (bitsIndex == bits.length) { + bitsIndex = 0; + if (!nextRowY()) { + return next = false; + } + } + } while (bitBuffer == 0); + zz = bz + (((bitsIndex - 1) << 2) & 15); + yy = by + ((bitsIndex - 1) >> 2); + } + return true; + } + + @Override + public boolean hasNext() { + return next; + } + + @Override + public BlockVector3 next() { + final long lowBit = Long.lowestOneBit(bitBuffer); + final int bitIndex = Long.bitCount(lowBit-1); + { + mutable.setComponents((bx) + (bitIndex & 15), yy, (zz) + (bitIndex)); + } + bitBuffer = bitBuffer ^ lowBit; + nextLong(); + return mutable; + } + + @Override + public void remove() { + // TODO optimize + MemBlockSet.this.remove(mutable); + } + }; + } + + @Override + public boolean isEmpty() { + for (int X = 0; X < rows.length; X++) { + IRow nullRowX = rows[X]; + if (!(nullRowX instanceof RowX)) continue; + RowX rowx = (RowX) nullRowX; + for (int Z = 0; Z < rowx.rows.length; Z++) { + IRow nullRowZ = rowx.rows[Z]; + if (!(nullRowZ instanceof RowZ)) continue; + RowZ rowz = (RowZ) nullRowZ; + for (int Y = 0; Y < 16; Y++) { + IRow nullRowY = rowz.rows[Y]; + if (!(nullRowY instanceof RowY)) continue; + RowY rowY = (RowY) nullRowY; + for (long bit : rowY.bits) { + if (bit != 0) return true; + } + } + } + } + return false; + } + + @Override + public int size() { + return (int) sizeLong(); + } + + public long sizeLong() { + long total = 0; + long lastBit = 0; + int lastCount = 0; + for (int X = 0; X < rows.length; X++) { + IRow nullRowX = rows[X]; + if (!(nullRowX instanceof RowX)) continue; + RowX rowx = (RowX) nullRowX; + for (int Z = 0; Z < rowx.rows.length; Z++) { + IRow nullRowZ = rowx.rows[Z]; + if (!(nullRowZ instanceof RowZ)) continue; + RowZ rowz = (RowZ) nullRowZ; + outer: + for (int Y = 0; Y < 16; Y++) { + IRow nullRowY = rowz.rows[Y]; + if (!(nullRowY instanceof RowY)) continue; + RowY rowY = (RowY) nullRowY; + for (long bit : rowY.bits) { + if (bit == 0) continue; + else if (bit == -1L) { + total += 64; + } + else if (bit == lastBit) { + total += lastCount; + } else { + lastBit = bit; + total += lastCount = Long.bitCount(bit); + } + } + } + } + } + return total; + } + + public void clear() { + Arrays.fill(rows, NULL_ROW_X); + } + + public interface BlockIterator { + void apply(int x, int y, int z); + } + + private interface IRow { + default boolean get(IRow[] rows, int x, int y, int z) { return false; } + void set(IRow[] rows, int x, int y, int z); + default boolean add(IRow[] rows, int x, int y, int z) { + set(rows, x, y, z); + return true; + } + default boolean remove(IRow[] rows, int x, int y, int z) { + remove(rows, x, y, z); + return false; + } + default void clear(IRow[] rows, int x, int y, int z) { return; } + } + + private static final class NullRowX implements IRow { + @Override + public void set(IRow[] parent, int x, int y, int z) { + IRow row = new RowX(parent.length); + parent[x >> 4] = row; + row.set(parent, x, y, z); + } + } + + private static final class NullRowZ implements IRow { + @Override + public void set(IRow[] parent, int x, int y, int z) { + IRow row = new RowZ(); + parent[z >> 4] = row; + row.set(parent, x, y, z); + } + } + + private static final class NullRowY implements IRow { + @Override + public void set(IRow[] parent, int x, int y, int z) { + IRow row = new RowY(); + parent[y >> 4] = row; + row.set(parent, x, y, z); + } + } + + private static final class RowX implements IRow { + private final IRow[] rows; + + public RowX(int size) { + this.rows = new IRow[size]; + for (int i = 0; i < size; i++) rows[i] = NULL_ROW_Z; + } + + @Override + public boolean get(IRow[] parent, int x, int y, int z) { + return rows[z >> 4].get(this.rows, x, y, z); + } + + @Override + public void set(IRow[] parent, int x, int y, int z) { + this.rows[z >> 4].set(this.rows, x, y, z); + } + + @Override + public boolean add(IRow[] parent, int x, int y, int z) { + return this.rows[z >> 4].add(this.rows, x, y, z); + } + + @Override + public void clear(IRow[] parent, int x, int y, int z) { + this.rows[z >> 4].clear(this.rows, x, y, z); + } + + @Override + public boolean remove(IRow[] parent, int x, int y, int z) { + return this.rows[z >> 4].remove(this.rows, x, y, z); + } + } + + private static final class RowZ implements IRow { + private final IRow[] rows; + + public RowZ() { + this.rows = new IRow[CHUNK_LAYERS]; + for (int i = 0; i < CHUNK_LAYERS; i++) rows[i] = NULL_ROW_Y; + } + + @Override + public boolean get(IRow[] parent, int x, int y, int z) { + return rows[y >> 4].get(this.rows, x, y, z); + } + + @Override + public void set(IRow[] parent, int x, int y, int z) { + this.rows[y >> 4].set(this.rows, x, y, z); + } + + @Override + public boolean add(IRow[] parent, int x, int y, int z) { + return this.rows[y >> 4].add(this.rows, x, y, z); + } + + @Override + public void clear(IRow[] parent, int x, int y, int z) { + this.rows[y >> 4].set(this.rows, x, y, z); + } + + @Override + public boolean remove(IRow[] parent, int x, int y, int z) { + return this.rows[y >> 4].remove(this.rows, x, y, z); + } + } + + private static final class RowY implements IRow { + private final long[] bits; + + public RowY() { + this.bits = new long[WORDS]; + } + + @Override + public boolean get(IRow[] parent, int x, int y, int z) { + int i = ((y & 15) << 8) | ((z & 15) << 4) | (x & 15); + return (bits[i >> 6] & (1L << (i & 0x3F))) != 0; + } + + @Override + public void set(IRow[] parent, int x, int y, int z) { + int i = ((y & 15) << 8) | ((z & 15) << 4) | (x & 15); + bits[i >> 6] |= (1L << (i & 0x3F)); + } + + @Override + public boolean add(IRow[] parent, int x, int y, int z) { + int i = ((y & 15) << 8) | ((z & 15) << 4) | (x & 15); + int offset = i >> 6; + long value = bits[offset]; + long mask = (1L << (i & 0x3F)); + if ((value & mask) == 0) { + bits[offset] = value | mask; + return true; + } + return false; + } + + @Override + public void clear(IRow[] parent, int x, int y, int z) { + int i = ((y & 15) << 8) | ((z & 15) << 4) | (x & 15); + bits[i >> 6] &= ~(1L << (i & 0x3F)); + } + + @Override + public boolean remove(IRow[] rows, int x, int y, int z) { + int i = ((y & 15) << 8) | ((z & 15) << 4) | (x & 15); + int offset = i >> 6; + long value = bits[offset]; + long mask = (1L << (i & 0x3F)); + if ((value & mask) != 0) { + bits[offset] = value & ~mask; + return true; + } + return false; + } + } + + private static IRow[] resize(IRow[] arr, IRow def) { + int len = arr.length; + int newLen = len == 1 ? 1 : Integer.highestOneBit(len - 1) * 2; + IRow[] copy = Arrays.copyOf(arr, newLen, IRow[].class); + for (int i = len; i < newLen; i++) copy[i] = def; + return copy; + } +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/exception/FaweException.java b/worldedit-core/src/main/java/com/boydti/fawe/object/exception/FaweException.java index 78e66b366..1c3726905 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/exception/FaweException.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/exception/FaweException.java @@ -3,6 +3,17 @@ package com.boydti.fawe.object.exception; import com.boydti.fawe.config.BBC; public class FaweException extends RuntimeException { + public static final FaweChunkLoadException CHUNK = new FaweChunkLoadException(); + public static final FaweBlockBagException BLOCK_BAG = new FaweBlockBagException(); + public static final FaweException MANUAL = new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MANUAL); + public static final FaweException NO_REGION = new FaweException(BBC.WORLDEDIT_CANCEL_REASON_NO_REGION); + public static final FaweException OUTSIDE_REGION = new FaweException(BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); + public static final FaweException MAX_CHECKS = new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); + public static final FaweException MAX_CHANGES = new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES); + public static final FaweException LOW_MEMORY = new FaweException(BBC.WORLDEDIT_CANCEL_REASON_LOW_MEMORY); + public static final FaweException MAX_ENTITIES = new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_ENTITIES); + public static final FaweException MAX_TILES = new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_TILES); + private final BBC message; public FaweException(BBC reason) { @@ -42,7 +53,7 @@ public class FaweException extends RuntimeException { } /** - * Faster exception throwing if you don't fill the stacktrace + * Faster exception throwing/handling if you don't fill the stacktrace * * @return */ diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/BlockTranslateExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/BlockTranslateExtent.java index 625d2687c..1b35bf82f 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/BlockTranslateExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/BlockTranslateExtent.java @@ -52,17 +52,12 @@ public class BlockTranslateExtent extends AbstractDelegateExtent { @Override public BlockState getBlock(BlockVector3 location) { - return getLazyBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + return getBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ()); } @Override - public BlockState getLazyBlock(BlockVector3 location) { - return getLazyBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - } - - @Override - public BlockState getLazyBlock(int x, int y, int z) { - return super.getLazyBlock(x + dx, y + dy, z + dz); + public BlockState getBlock(int x, int y, int z) { + return super.getBlock(x + dx, y + dy, z + dz); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/FastWorldEditExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/FastWorldEditExtent.java index 48a2ad169..044513d72 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/FastWorldEditExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/FastWorldEditExtent.java @@ -127,12 +127,12 @@ public class FastWorldEditExtent extends AbstractDelegateExtent implements HasFa } @Override - public BlockState getLazyBlock(BlockVector3 location) { - return getLazyBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + public BlockState getBlock(BlockVector3 location) { + return getBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ()); } @Override - public BlockState getLazyBlock(int x, int y, int z) { + public BlockState getBlock(int x, int y, int z) { int combinedId4Data = queue.getCombinedId4Data(x, y, z, 0); BlockType type = BlockTypes.getFromStateId(combinedId4Data); return type.withStateId(combinedId4Data); @@ -162,11 +162,6 @@ public class FastWorldEditExtent extends AbstractDelegateExtent implements HasFa return world.getEntities(region); } - @Override - public BlockState getBlock(final BlockVector3 position) { - return this.getLazyBlock(position); - } - @Override public boolean setBiome(final BlockVector2 position, final BiomeType biome) { queue.setBiome(position.getBlockX(), position.getBlockZ(), biome); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/FaweRegionExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/FaweRegionExtent.java index 7e81e7283..7d2304482 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/FaweRegionExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/FaweRegionExtent.java @@ -2,6 +2,7 @@ package com.boydti.fawe.object.extent; import com.boydti.fawe.config.BBC; import com.boydti.fawe.object.FaweLimit; +import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.util.WEManager; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; @@ -57,44 +58,22 @@ public abstract class FaweRegionExtent extends ResettableExtent { return contains(p.getBlockX(), p.getBlockZ()); } - @Override - public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { - if (!contains(location)) { - if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); - } - return false; - } - return super.setBlock(location, block); - } - @Override public > boolean setBlock(int x, int y, int z, B block) throws WorldEditException { if (!contains(x, y, z)) { if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); + WEManager.IMP.cancelEditSafe(this, FaweException.OUTSIDE_REGION); } return false; } return super.setBlock(x, y, z, block); } - @Override - public boolean setBiome(BlockVector2 position, BiomeType biome) { - if (!contains(position)) { - if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); - } - return false; - } - return super.setBiome(position, biome); - } - @Override public boolean setBiome(int x, int y, int z, BiomeType biome) { if (!contains(x, y, z)) { if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); + WEManager.IMP.cancelEditSafe(this, FaweException.OUTSIDE_REGION); } return false; } @@ -105,18 +84,29 @@ public abstract class FaweRegionExtent extends ResettableExtent { public BiomeType getBiome(BlockVector2 position) { if (!contains(position)) { if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); + WEManager.IMP.cancelEditSafe(this, FaweException.OUTSIDE_REGION); } return null; } return super.getBiome(position); } + @Override + public BiomeType getBiomeType(int x, int z) { + if (!contains(x, z)) { + if (!limit.MAX_FAILS()) { + WEManager.IMP.cancelEditSafe(this, FaweException.OUTSIDE_REGION); + } + return null; + } + return super.getBiomeType(x, z); + } + @Override public BaseBlock getFullBlock(BlockVector3 position) { if (!contains(position)) { if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); + WEManager.IMP.cancelEditSafe(this, FaweException.OUTSIDE_REGION); } return BlockTypes.AIR.getDefaultState().toBaseBlock(); } @@ -127,40 +117,18 @@ public abstract class FaweRegionExtent extends ResettableExtent { public BlockState getBlock(BlockVector3 position) { if (!contains(position)) { if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); + WEManager.IMP.cancelEditSafe(this, FaweException.OUTSIDE_REGION); } return BlockTypes.AIR.getDefaultState(); } return super.getBlock(position); } - @Override - public BlockState getLazyBlock(BlockVector3 position) { - if (!contains(position)) { - if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); - } - return BlockTypes.AIR.getDefaultState(); - } - return super.getLazyBlock(position); - } - - @Override - public BlockState getLazyBlock(int x, int y, int z) { - if (!contains(x, y, z)) { - if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); - } - return BlockTypes.AIR.getDefaultState(); - } - return super.getLazyBlock(x, y, z); - } - @Override public int getBlockLight(int x, int y, int z) { if (!contains(x, y, z)) { if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); + WEManager.IMP.cancelEditSafe(this, FaweException.OUTSIDE_REGION); } return 0; } @@ -171,7 +139,7 @@ public abstract class FaweRegionExtent extends ResettableExtent { public int getBrightness(int x, int y, int z) { if (!contains(x, y, z)) { if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); + WEManager.IMP.cancelEditSafe(this, FaweException.OUTSIDE_REGION); } return 0; } @@ -182,7 +150,7 @@ public abstract class FaweRegionExtent extends ResettableExtent { public int getLight(int x, int y, int z) { if (!contains(x, y, z)) { if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); + WEManager.IMP.cancelEditSafe(this, FaweException.OUTSIDE_REGION); } return 0; } @@ -193,7 +161,7 @@ public abstract class FaweRegionExtent extends ResettableExtent { public int getOpacity(int x, int y, int z) { if (!contains(x, y, z)) { if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); + WEManager.IMP.cancelEditSafe(this, FaweException.OUTSIDE_REGION); } return 0; } @@ -204,7 +172,7 @@ public abstract class FaweRegionExtent extends ResettableExtent { public int getSkyLight(int x, int y, int z) { if (!contains(x, y, z)) { if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); + WEManager.IMP.cancelEditSafe(this, FaweException.OUTSIDE_REGION); } return 0; } @@ -216,7 +184,7 @@ public abstract class FaweRegionExtent extends ResettableExtent { public Entity createEntity(Location location, BaseEntity entity) { if (!contains(location.getBlockX(), location.getBlockY(), location.getBlockZ())) { if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); + WEManager.IMP.cancelEditSafe(this, FaweException.OUTSIDE_REGION); } return null; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/MemoryCheckingExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/MemoryCheckingExtent.java index 9503ade76..72f7583cb 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/MemoryCheckingExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/MemoryCheckingExtent.java @@ -2,6 +2,7 @@ package com.boydti.fawe.object.extent; import com.boydti.fawe.config.BBC; import com.boydti.fawe.object.FawePlayer; +import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.util.MemUtil; import com.boydti.fawe.util.Perm; import com.boydti.fawe.util.WEManager; @@ -30,7 +31,7 @@ public class MemoryCheckingExtent extends AbstractDelegateExtent { BBC.WORLDEDIT_OOM_ADMIN.send(this.player); } } - WEManager.IMP.cancelEdit(this, BBC.WORLDEDIT_CANCEL_REASON_LOW_MEMORY); + WEManager.IMP.cancelEdit(this, FaweException.LOW_MEMORY); return false; } return true; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/MultiTransform.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/MultiTransform.java index 95b652ecd..475a18a07 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/MultiTransform.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/MultiTransform.java @@ -28,7 +28,7 @@ public class MultiTransform extends RandomTransform { @Override public void add(ResettableExtent extent, double chance) { super.add(extent, chance); - this.extents = getExtents().toArray(new ResettableExtent[getExtents().size()]); + this.extents = getExtents().toArray(new ResettableExtent[0]); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/NullExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/NullExtent.java index ae1d1c7be..157064697 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/NullExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/NullExtent.java @@ -3,9 +3,8 @@ package com.boydti.fawe.object.extent; import com.boydti.fawe.config.BBC; import com.boydti.fawe.object.FaweLimit; import com.boydti.fawe.object.exception.FaweException; + import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.Extent; @@ -15,6 +14,8 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import javax.annotation.Nullable; @@ -25,7 +26,7 @@ import java.util.List; public class NullExtent extends FaweRegionExtent { - private final BBC reason; + private final FaweException reason; /** * Create a new instance. @@ -33,15 +34,18 @@ public class NullExtent extends FaweRegionExtent { * @param extent the extent */ public NullExtent(Extent extent, BBC failReason) { + this(extent, new FaweException(failReason)); + } + + public NullExtent(Extent extent, FaweException exception) { super(extent, FaweLimit.MAX); - this.reason = failReason; + this.reason = exception; } public NullExtent() { - super(new com.sk89q.worldedit.extent.NullExtent(), FaweLimit.MAX); - this.reason = BBC.WORLDEDIT_CANCEL_REASON_MANUAL; + this(new com.sk89q.worldedit.extent.NullExtent(), FaweException.MANUAL); } - + @Override public ResettableExtent setExtent(Extent extent) { return this; @@ -50,73 +54,65 @@ public class NullExtent extends FaweRegionExtent { @Override public BiomeType getBiome(final BlockVector2 arg0) { if(reason != null) { - throw new FaweException(reason); - }else { - return null; + throw reason; } + return null; } @Override public BlockState getBlock(final BlockVector3 arg0) { if(reason != null) { - throw new FaweException(reason); - }else { - return null; + throw reason; } + return null; } @Override - public BlockState getLazyBlock(final BlockVector3 arg0) { + public BlockState getBlock(int x, int y, int z) { if(reason != null) { - throw new FaweException(reason); - }else { - return null; + throw reason; } + return null; + } + + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + if(reason != null) { + throw reason; + } + return null; } @Override public boolean setBiome(final BlockVector2 arg0, final BiomeType arg1) { if(reason != null) { - throw new FaweException(reason); - }else { - return false; + throw reason; } + return false; } @Override public boolean setBlock(final BlockVector3 arg0, final BlockStateHolder arg1) throws WorldEditException { if(reason != null) { - throw new FaweException(reason); - }else { - return false; + throw reason; } + return false; } @Override public boolean setBlock(int x, int y, int z, BlockStateHolder block) throws WorldEditException { if(reason != null) { - throw new FaweException(reason); - }else { - return false; - } - } - - @Override - public BlockState getLazyBlock(int x, int y, int z) { - if(reason != null) { - throw new FaweException(reason); - }else { - return null; + throw reason; } + return false; } @Override public Entity createEntity(final Location arg0, final BaseEntity arg1) { if(reason != null) { - throw new FaweException(reason); - }else { - return null; + throw reason; } + return null; } @Override @@ -131,30 +127,28 @@ public class NullExtent extends FaweRegionExtent { @Override public BlockVector3 getMaximumPoint() { - return BlockVector3.at(0, 0, 0); + return BlockVector3.ZERO; } @Override public BlockVector3 getMinimumPoint() { - return BlockVector3.at(0, 0, 0); + return BlockVector3.ZERO; } @Override public boolean contains(int x, int z) { if(reason != null) { - throw new FaweException(reason); - }else { - return false; + throw reason; } + return false; } @Override public boolean contains(int x, int y, int z) { if(reason != null) { - throw new FaweException(reason); - }else { - return false; + throw reason; } + return false; } @Override @@ -162,11 +156,6 @@ public class NullExtent extends FaweRegionExtent { return Collections.emptyList(); } - @Override - protected Operation commitBefore() { - return null; - } - @Nullable @Override public Operation commit() { @@ -176,28 +165,25 @@ public class NullExtent extends FaweRegionExtent { @Override public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) { if(reason != null) { - throw new FaweException(reason); - }else { - return -1; + throw reason; } + return -1; } @Override public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) { if(reason != null) { - throw new FaweException(reason); - }else { - return -1; + throw reason; } + return -1; } @Override public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) { if(reason != null) { - throw new FaweException(reason); - }else { - return -1; + throw reason; } + return -1; } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/PositionTransformExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/PositionTransformExtent.java index 29d8eae5b..c984a7ca9 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/PositionTransformExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/PositionTransformExtent.java @@ -46,13 +46,8 @@ public class PositionTransformExtent extends ResettableExtent { } @Override - public BlockState getLazyBlock(int x, int y, int z) { - return super.getLazyBlock(getPos(BlockVector3.at(x, y, z))); - } - - @Override - public BlockState getLazyBlock(BlockVector3 position) { - return super.getLazyBlock(getPos(position)); + public BlockState getBlock(int x, int y, int z) { + return super.getBlock(getPos(BlockVector3.at(x, y, z))); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/ProcessedWEExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/ProcessedWEExtent.java index d9a331f82..3aa689ada 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/ProcessedWEExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/ProcessedWEExtent.java @@ -2,10 +2,10 @@ package com.boydti.fawe.object.extent; import com.boydti.fawe.config.BBC; import com.boydti.fawe.object.FaweLimit; +import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.util.WEManager; + import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.AbstractDelegateExtent; @@ -15,6 +15,8 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockTypes; @@ -40,7 +42,7 @@ public class ProcessedWEExtent extends AbstractDelegateExtent { return null; } if (!limit.MAX_ENTITIES()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_ENTITIES); + WEManager.IMP.cancelEditSafe(this, FaweException.MAX_ENTITIES); return null; } return super.createEntity(location, entity); @@ -62,19 +64,19 @@ public class ProcessedWEExtent extends AbstractDelegateExtent { } @Override - public BlockState getLazyBlock(int x, int y, int z) { + public BlockState getBlock(int x, int y, int z) { if (!limit.MAX_CHECKS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); + WEManager.IMP.cancelEditSafe(this, FaweException.MAX_CHECKS); return BlockTypes.AIR.getDefaultState(); } else { - return extent.getLazyBlock(x, y, z); + return extent.getBlock(x, y, z); } } @Override public BaseBlock getFullBlock(BlockVector3 pos) { if (!limit.MAX_CHECKS()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); + WEManager.IMP.cancelEditSafe(this, FaweException.MAX_CHECKS); return BlockTypes.AIR.getDefaultState().toBaseBlock(); } else { return extent.getFullBlock(pos); @@ -87,8 +89,8 @@ public class ProcessedWEExtent extends AbstractDelegateExtent { } @Override - public BlockState getLazyBlock(BlockVector3 location) { - return getLazyBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + public BlockState getBlock(BlockVector3 location) { + return getBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ()); } @Override @@ -96,18 +98,18 @@ public class ProcessedWEExtent extends AbstractDelegateExtent { boolean hasNbt = block instanceof BaseBlock && ((BaseBlock)block).hasNbtData(); if (hasNbt) { if (!limit.MAX_BLOCKSTATES()) { - WEManager.IMP.cancelEdit(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_TILES); + WEManager.IMP.cancelEdit(this, FaweException.MAX_TILES); return false; } else { if (!limit.MAX_CHANGES()) { - WEManager.IMP.cancelEdit(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES); + WEManager.IMP.cancelEdit(this, FaweException.MAX_CHANGES); return false; } return extent.setBlock(x, y, z, block); } } if (!limit.MAX_CHANGES()) { - WEManager.IMP.cancelEdit(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES); + WEManager.IMP.cancelEdit(this, FaweException.MAX_CHANGES); return false; } else { return extent.setBlock(x, y, z, block); @@ -117,7 +119,7 @@ public class ProcessedWEExtent extends AbstractDelegateExtent { @Override public boolean setBiome(final BlockVector2 position, final BiomeType biome) { if (!limit.MAX_CHANGES()) { - WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES); + WEManager.IMP.cancelEditSafe(this, FaweException.MAX_CHANGES); return false; } return super.setBiome(position, biome); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/ResettableExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/ResettableExtent.java index 566d3c740..b806c004e 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/ResettableExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/ResettableExtent.java @@ -26,9 +26,7 @@ public class ResettableExtent extends AbstractDelegateExtent implements Serializ setOrigin(pos); } - protected void setOrigin(BlockVector3 pos) { - - } + protected void setOrigin(BlockVector3 pos) {} public ResettableExtent setExtent(Extent extent) { checkNotNull(extent); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/StripNBTExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/StripNBTExtent.java index 0d69f4259..9ad71eefb 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/StripNBTExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/StripNBTExtent.java @@ -30,7 +30,7 @@ public class StripNBTExtent extends AbstractDelegateExtent { */ public StripNBTExtent(Extent extent, Set strip) { super(extent); - this.strip = strip.toArray(new String[strip.size()]); + this.strip = strip.toArray(new String[0]); } @Override @@ -60,7 +60,7 @@ public class StripNBTExtent extends AbstractDelegateExtent { } return (B) localBlock; } - + public T stripEntityNBT(T entity) { if (!entity.hasNbtData()) return entity; CompoundTag nbt = entity.getNbtData(); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/TemporalExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/TemporalExtent.java index 6005c0d8d..96e61de59 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/TemporalExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/TemporalExtent.java @@ -57,19 +57,11 @@ public class TemporalExtent extends AbstractDelegateExtent { } @Override - public BlockState getLazyBlock(BlockVector3 position) { - if (position.getX() == x && position.getY() == y && position.getZ() == z) { - return block.toImmutableState(); - } - return super.getLazyBlock(position); - } - - @Override - public BlockState getLazyBlock(int x, int y, int z) { + public BlockState getBlock(int x, int y, int z) { if (this.x == x && this.y == y && this.z == z) { return block.toImmutableState(); } - return super.getLazyBlock(x, y, z); + return super.getBlock(x, y, z); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/TransformExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/TransformExtent.java index 910c7a9e8..f2be69cf1 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/TransformExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/TransformExtent.java @@ -1,6 +1,7 @@ package com.boydti.fawe.object.extent; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.extent.Extent; @@ -14,7 +15,8 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; public class TransformExtent extends BlockTransformExtent { - private final MutableBlockVector3 mutable = new MutableBlockVector3(); + private final MutableVector3 mutable1 = new MutableVector3(); + private final MutableBlockVector3 mutable2 = new MutableBlockVector3(); private BlockVector3 min; public TransformExtent(Extent parent) { @@ -50,43 +52,34 @@ public class TransformExtent extends BlockTransformExtent { if (min == null) { min = pos; } - mutable.mutX(((pos.getX() - min.getX()))); - mutable.mutY(((pos.getY() - min.getY()))); - mutable.mutZ(((pos.getZ() - min.getZ()))); - MutableVector3 tmp = new MutableVector3(getTransform().apply(mutable.toVector3())); - tmp.mutX((tmp.getX() + min.getX())); - tmp.mutY((tmp.getY() + min.getY())); - tmp.mutZ((tmp.getZ() + min.getZ())); - return tmp.toBlockPoint(); + mutable1.mutX(((pos.getX() - min.getX()))); + mutable1.mutY(((pos.getY() - min.getY()))); + mutable1.mutZ(((pos.getZ() - min.getZ()))); + Vector3 tmp = getTransform().apply(mutable1); + mutable2.mutX((tmp.getX() + min.getX())); + mutable2.mutY((tmp.getY() + min.getY())); + mutable2.mutZ((tmp.getZ() + min.getZ())); + return mutable2; } public BlockVector3 getPos(int x, int y, int z) { if (min == null) { min = BlockVector3.at(x, y, z); } - mutable.mutX(((x - min.getX()))); - mutable.mutY(((y - min.getY()))); - mutable.mutZ(((z - min.getZ()))); - MutableVector3 tmp = new MutableVector3(getTransform().apply(mutable.toVector3())); - tmp.mutX((tmp.getX() + min.getX())); - tmp.mutY((tmp.getY() + min.getY())); - tmp.mutZ((tmp.getZ() + min.getZ())); + mutable1.mutX(((x - min.getX()))); + mutable1.mutY(((y - min.getY()))); + mutable1.mutZ(((z - min.getZ()))); + Vector3 tmp = getTransform().apply(mutable1); + mutable2.mutX((tmp.getX() + min.getX())); + mutable2.mutY((tmp.getY() + min.getY())); + mutable2.mutZ((tmp.getZ() + min.getZ())); return tmp.toBlockPoint(); } @Override - public BlockState getLazyBlock(int x, int y, int z) { - return transform(super.getLazyBlock(getPos(x, y, z))); - } - - @Override - public BlockState getLazyBlock(BlockVector3 position) { - return transform(super.getLazyBlock(getPos(position))); - } - - @Override - public BlockState getBlock(BlockVector3 position) { - return transform(super.getBlock(getPos(position))); + public BlockState getBlock(int x, int y, int z) { + BlockVector3 p = getPos(x, y, z); + return transform(super.getBlock(p.getX(), p.getY(), p.getZ())); } @Override @@ -95,11 +88,9 @@ public class TransformExtent extends BlockTransformExtent { } @Override - public BiomeType getBiome(BlockVector2 position) { - mutable.mutX(position.getBlockX()); - mutable.mutZ(position.getBlockZ()); - mutable.mutY(0); - return super.getBiome(getPos(mutable).toBlockVector2()); + public BiomeType getBiomeType(int x, int z) { + BlockVector3 p = getPos(x, 0, z); + return super.getBiomeType(p.getX(), p.getZ()); } @Override @@ -114,10 +105,8 @@ public class TransformExtent extends BlockTransformExtent { } @Override - public boolean setBiome(BlockVector2 position, BiomeType biome) { - mutable.mutX(position.getBlockX()); - mutable.mutZ(position.getBlockZ()); - mutable.mutY(0); - return super.setBiome(getPos(mutable).toBlockVector2(), biome); + public boolean setBiome(int x, int y, int z, BiomeType biome) { + BlockVector3 p = getPos(x, y, z); + return super.setBiome(p.getX(), p.getY(), p.getZ(), biome); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/AdjacentAnyMask2.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/AdjacentAnyMask2.java new file mode 100644 index 000000000..8cb5f6ffc --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/AdjacentAnyMask2.java @@ -0,0 +1,11 @@ +package com.boydti.fawe.object.mask; + +import com.sk89q.worldedit.function.mask.AbstractMask; +import com.sk89q.worldedit.math.BlockVector3; + +public class AdjacentAnyMask2 extends AbstractMask { + @Override + public boolean test(BlockVector3 vector) { + return false; + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/AngleMask.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/AngleMask.java index b1f00b91c..430651602 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/AngleMask.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/AngleMask.java @@ -1,13 +1,11 @@ package com.boydti.fawe.object.mask; import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.function.mask.Mask2D; import com.sk89q.worldedit.function.mask.SolidBlockMask; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.MutableBlockVector3; import java.util.Arrays; -import javax.annotation.Nullable; public class AngleMask extends SolidBlockMask implements ResettableMask { public static double ADJACENT_MOD = 0.5; @@ -160,9 +158,4 @@ public class AngleMask extends SolidBlockMask implements ResettableMask { return testSlope(x, y, z); } - @Nullable - @Override - public Mask2D toMask2D() { - return null; - } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/BlockLightMask.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/BlockLightMask.java index dfab059a2..815a7fc2c 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/BlockLightMask.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/BlockLightMask.java @@ -28,9 +28,4 @@ public class BlockLightMask extends AbstractExtentMask { return false; } - @Nullable - @Override - public Mask2D toMask2D() { - return null; - } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/BrightnessMask.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/BrightnessMask.java index 099a47b2f..9b08f93c0 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/BrightnessMask.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/BrightnessMask.java @@ -1,13 +1,11 @@ package com.boydti.fawe.object.mask; import com.boydti.fawe.object.extent.LightingExtent; + import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.mask.AbstractExtentMask; -import com.sk89q.worldedit.function.mask.Mask2D; import com.sk89q.worldedit.math.BlockVector3; -import javax.annotation.Nullable; - public class BrightnessMask extends AbstractExtentMask { private final int min, max; @@ -28,9 +26,4 @@ public class BrightnessMask extends AbstractExtentMask { return false; } - @Nullable - @Override - public Mask2D toMask2D() { - return null; - } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/DataMask.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/DataMask.java index 01afbac85..2d1e3ae9e 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/DataMask.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/DataMask.java @@ -2,11 +2,8 @@ package com.boydti.fawe.object.mask; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.mask.AbstractExtentMask; -import com.sk89q.worldedit.function.mask.Mask2D; import com.sk89q.worldedit.math.BlockVector3; -import javax.annotation.Nullable; - public class DataMask extends AbstractExtentMask implements ResettableMask { public DataMask(Extent extent) { @@ -19,9 +16,9 @@ public class DataMask extends AbstractExtentMask implements ResettableMask { public boolean test(BlockVector3 vector) { Extent extent = getExtent(); if (data != -1) { - return extent.getLazyBlock(vector).getInternalPropertiesId() == data; + return extent.getBlock(vector).getInternalPropertiesId() == data; } else { - data = extent.getLazyBlock(vector).getInternalPropertiesId(); + data = extent.getBlock(vector).getInternalPropertiesId(); return true; } } @@ -31,9 +28,4 @@ public class DataMask extends AbstractExtentMask implements ResettableMask { this.data = -1; } - @Nullable - @Override - public Mask2D toMask2D() { - return null; - } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/IdDataMask.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/IdDataMask.java index 7b7705172..2782dc5a4 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/IdDataMask.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/IdDataMask.java @@ -1,13 +1,9 @@ package com.boydti.fawe.object.mask; -import com.boydti.fawe.FaweCache; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.mask.AbstractExtentMask; -import com.sk89q.worldedit.function.mask.Mask2D; import com.sk89q.worldedit.math.BlockVector3; -import javax.annotation.Nullable; - public class IdDataMask extends AbstractExtentMask implements ResettableMask { private transient int combined = -1; @@ -19,9 +15,9 @@ public class IdDataMask extends AbstractExtentMask implements ResettableMask { public boolean test(BlockVector3 vector) { Extent extent = getExtent(); if (combined != -1) { - return extent.getLazyBlock(vector).getInternalId() == combined; + return extent.getBlock(vector).getInternalId() == combined; } else { - combined = extent.getLazyBlock(vector).getInternalId(); + combined = extent.getBlock(vector).getInternalId(); return true; } } @@ -31,9 +27,4 @@ public class IdDataMask extends AbstractExtentMask implements ResettableMask { this.combined = -1; } - @Nullable - @Override - public Mask2D toMask2D() { - return null; - } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/IdMask.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/IdMask.java index e9b36b365..38b0d8b7c 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/IdMask.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/IdMask.java @@ -19,9 +19,9 @@ public class IdMask extends AbstractExtentMask implements ResettableMask { public boolean test(BlockVector3 vector) { Extent extent = getExtent(); if (id != -1) { - return extent.getLazyBlock(vector).getInternalBlockTypeId() == id; + return extent.getBlock(vector).getInternalBlockTypeId() == id; } else { - id = extent.getLazyBlock(vector).getInternalBlockTypeId(); + id = extent.getBlock(vector).getInternalBlockTypeId(); return true; } } @@ -31,9 +31,4 @@ public class IdMask extends AbstractExtentMask implements ResettableMask { this.id = -1; } - @Nullable - @Override - public Mask2D toMask2D() { - return null; - } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/LightMask.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/LightMask.java index 1ebbfbce1..8489124ec 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/LightMask.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/LightMask.java @@ -27,9 +27,4 @@ public class LightMask extends AbstractExtentMask { return false; } - @Nullable - @Override - public Mask2D toMask2D() { - return null; - } -} \ No newline at end of file +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/OpacityMask.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/OpacityMask.java index 7279b8b1a..8d35f884e 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/OpacityMask.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/OpacityMask.java @@ -27,9 +27,4 @@ public class OpacityMask extends AbstractExtentMask { return false; } - @Nullable - @Override - public Mask2D toMask2D() { - return null; - } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/PlaneMask.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/PlaneMask.java index f0f9c3fe1..ba22cbe75 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/PlaneMask.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/PlaneMask.java @@ -61,9 +61,4 @@ public class PlaneMask extends AbstractMask implements ResettableMask { mode = -1; } - @Nullable - @Override - public Mask2D toMask2D() { - return null; - } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/RadiusMask.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/RadiusMask.java index 5759aabba..0ece9ff56 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/RadiusMask.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/RadiusMask.java @@ -44,9 +44,4 @@ public class RadiusMask extends AbstractMask implements ResettableMask { return true; } - @Nullable - @Override - public Mask2D toMask2D() { - return null; - } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/SkyLightMask.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/SkyLightMask.java index 8b796d3ac..3be2f710f 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/SkyLightMask.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/SkyLightMask.java @@ -27,9 +27,4 @@ public class SkyLightMask extends AbstractExtentMask { return false; } - @Nullable - @Override - public Mask2D toMask2D() { - return null; - } -} \ No newline at end of file +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/SolidPlaneMask.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/SolidPlaneMask.java index a999938e6..144397237 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/SolidPlaneMask.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/SolidPlaneMask.java @@ -88,9 +88,4 @@ public class SolidPlaneMask extends SolidBlockMask implements ResettableMask { mutable = new MutableBlockVector3(); } - @Nullable - @Override - public Mask2D toMask2D() { - return null; - } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/SurfaceMask.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/SurfaceMask.java index cd740f93f..dafc52a9b 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/SurfaceMask.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/SurfaceMask.java @@ -7,11 +7,8 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BlockTypes; public class SurfaceMask extends AdjacentAnyMask { - private final transient Extent extent; - public SurfaceMask(Extent extent) { super(getMask(extent)); - this.extent = extent; } public static Mask getMask(Extent extent) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/XAxisMask.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/XAxisMask.java index 44e1a3263..109eea2f3 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/XAxisMask.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/XAxisMask.java @@ -26,9 +26,4 @@ public class XAxisMask extends AbstractMask implements ResettableMask { this.layer = -1; } - @Nullable - @Override - public Mask2D toMask2D() { - return null; - } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/YAxisMask.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/YAxisMask.java index 2d333cb5f..239adec59 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/YAxisMask.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/YAxisMask.java @@ -1,11 +1,8 @@ package com.boydti.fawe.object.mask; import com.sk89q.worldedit.function.mask.AbstractMask; -import com.sk89q.worldedit.function.mask.Mask2D; import com.sk89q.worldedit.math.BlockVector3; -import javax.annotation.Nullable; - /** * Restricts the */ @@ -26,9 +23,4 @@ public class YAxisMask extends AbstractMask implements ResettableMask { this.layer = -1; } - @Nullable - @Override - public Mask2D toMask2D() { - return null; - } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/ZAxisMask.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/ZAxisMask.java index 15dd3cb36..cf8c082df 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/ZAxisMask.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/ZAxisMask.java @@ -26,9 +26,4 @@ public class ZAxisMask extends AbstractMask implements ResettableMask { this.layer = -1; } - @Nullable - @Override - public Mask2D toMask2D() { - return null; - } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AngleColorPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AngleColorPattern.java index f11fc4896..d94340204 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AngleColorPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AngleColorPattern.java @@ -1,7 +1,6 @@ package com.boydti.fawe.object.pattern; -import com.boydti.fawe.Fawe; -import com.boydti.fawe.FaweCache; +import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.object.DataAnglePattern; import com.boydti.fawe.util.TextureHolder; import com.sk89q.worldedit.WorldEditException; @@ -12,14 +11,12 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; -import java.io.IOException; - public class AngleColorPattern extends DataAnglePattern { - protected transient TextureHolder util; + protected transient TextureHolder holder; - public AngleColorPattern(Extent extent, TextureHolder util, int distance) { + public AngleColorPattern(Extent extent, TextureHolder holder, int distance) { super(extent, distance); - this.util = util; + this.holder = holder.getTextureUtil(); } public int getColor(int color, int slope) { @@ -34,24 +31,24 @@ public class AngleColorPattern extends DataAnglePattern { @Override public BaseBlock apply(BlockVector3 position) { BaseBlock block = extent.getFullBlock(position); - int slope = getSlope(block, position); + int slope = getSlope(block, position, extent); if (slope == -1) return block; - int color = util.getTextureUtil().getColor(block.getBlockType()); + int color = holder.getTextureUtil().getColor(block.getBlockType()); if (color == 0) return block; int newColor = getColor(color, slope); - return util.getTextureUtil().getNearestBlock(newColor).getDefaultState().toBaseBlock(); + return holder.getTextureUtil().getNearestBlock(newColor).getDefaultState().toBaseBlock(); } @Override - public int getSlope(BlockStateHolder block, BlockVector3 vector) { - int slope = super.getSlope(block, vector); + public int getSlope(BlockStateHolder block, BlockVector3 vector, Extent extent) { + int slope = super.getSlope(block, vector, extent); if (slope != -1) { int x = vector.getBlockX(); int y = vector.getBlockY(); int z = vector.getBlockZ(); int height = extent.getNearestSurfaceTerrainBlock(x, z, y, 0, maxY); if (height > 0) { - BlockStateHolder below = extent.getLazyBlock(x, height - 1, z); + BlockStateHolder below = extent.getBlock(x, height - 1, z); if (!below.getBlockType().getMaterial().isMovementBlocker()) { return Integer.MAX_VALUE; } @@ -61,20 +58,15 @@ public class AngleColorPattern extends DataAnglePattern { } @Override - public boolean apply(Extent extent, BlockVector3 setPosition, BlockVector3 getPosition) throws WorldEditException { - BlockStateHolder block = extent.getBlock(getPosition); - int slope = getSlope(block, getPosition); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + BlockStateHolder block = get.getBlock(extent); + int slope = getSlope(block, get, extent); if (slope == -1) return false; - int color = util.getTextureUtil().getColor(block.getBlockType()); + int color = holder.getTextureUtil().getColor(block.getBlockType()); if (color == 0) return false; int newColor = getColor(color, slope); - BlockType newBlock = util.getTextureUtil().getNearestBlock(newColor); + BlockType newBlock = holder.getTextureUtil().getNearestBlock(newColor); if (newBlock == null) return false; - return extent.setBlock(setPosition, newBlock.getDefaultState()); - } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - util = Fawe.get().getCachedTextureUtil(true, 0, 100); + return set.setBlock(extent, newBlock.getDefaultState()); } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/BiomePattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/BiomePattern.java index ff031dde7..1446feb74 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/BiomePattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/BiomePattern.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -10,7 +11,6 @@ import com.sk89q.worldedit.world.biome.BiomeType; import java.io.IOException; public class BiomePattern extends ExistingPattern { - private transient MutableBlockVector2 mutable = new MutableBlockVector2(); private final BiomeType biome; public BiomePattern(Extent extent, BiomeType biome) { @@ -24,8 +24,8 @@ public class BiomePattern extends ExistingPattern { } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 getPosition) throws WorldEditException { - return extent.setBiome(set.getBlockX(), set.getBlockY(), set.getBlockZ(), biome); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + return set.setBiome(extent, biome); } public class BiomePatternException extends RuntimeException { @@ -45,9 +45,4 @@ public class BiomePattern extends ExistingPattern { return this; } } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - mutable = new MutableBlockVector2(); - } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/BufferedPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/BufferedPattern.java index a9b9a5148..9bfafc9c5 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/BufferedPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/BufferedPattern.java @@ -1,6 +1,7 @@ package com.boydti.fawe.object.pattern; import com.boydti.fawe.Fawe; +import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.collection.LocalBlockVectorSet; import com.boydti.fawe.util.FaweTimer; @@ -17,17 +18,18 @@ import java.io.IOException; import java.util.UUID; public class BufferedPattern extends AbstractPattern implements ResettablePattern { - protected transient LocalBlockVectorSet set = new LocalBlockVectorSet(); - protected transient FaweTimer timer; - protected transient long[] actionTime; + protected final LocalBlockVectorSet set = new LocalBlockVectorSet(); + protected final FaweTimer timer; + protected final long[] actionTime; protected final Pattern pattern; protected final UUID uuid; public BufferedPattern(FawePlayer fp, Pattern parent) { this.uuid = fp.getUUID(); - this.actionTime = fp.getMeta("lastActionTime"); - if (actionTime == null) fp.setMeta("lastActionTime", actionTime = new long[2]); + long[] tmp = fp.getMeta("lastActionTime"); + if (tmp == null) fp.setMeta("lastActionTime", tmp = new long[2]); + actionTime = tmp; this.pattern = parent; this.timer = Fawe.get().getTimer(); } @@ -38,16 +40,12 @@ public class BufferedPattern extends AbstractPattern implements ResettablePatter } @Override - public boolean apply(Extent extent, BlockVector3 setPosition, BlockVector3 getPosition) throws WorldEditException { - long now = timer.getTick(); - try { - if (!set(setPosition)) { - return false; - } - return pattern.apply(extent, setPosition, getPosition); - } catch (UnsupportedOperationException ignore) { + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + actionTime[1] = timer.getTick(); + if (!set(get)) { + return false; } - return false; + return pattern.apply(extent, get, set); } public boolean set(BlockVector3 pos) { @@ -63,17 +61,4 @@ public class BufferedPattern extends AbstractPattern implements ResettablePatter actionTime[1] = actionTime[0]; actionTime[0] = now; } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - set = new LocalBlockVectorSet(); - timer = Fawe.get().getTimer(); - FawePlayer fp = Fawe.get().getCachedPlayer(uuid); - if (fp != null) { - this.actionTime = fp.getMeta("lastActionTime"); - if (actionTime == null) fp.setMeta("lastActionTime", actionTime = new long[2]); - } else { - actionTime = new long[2]; - } - } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/DataPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/DataPattern.java index 30c7d85f4..7b3b580d2 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/DataPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/DataPattern.java @@ -1,14 +1,14 @@ package com.boydti.fawe.object.pattern; -import com.boydti.fawe.FaweCache; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; +import com.boydti.fawe.beta.DelegateFilterBlock; +import com.boydti.fawe.beta.FilterBlock; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; -import com.sk89q.worldedit.world.block.BlockTypes; - import static com.google.common.base.Preconditions.checkNotNull; @@ -25,6 +25,24 @@ public class DataPattern extends AbstractExtentPattern { public BaseBlock apply(BlockVector3 position) { BaseBlock oldBlock = getExtent().getFullBlock(position); BaseBlock newBlock = pattern.apply(position); - return oldBlock.withPropertyId(newBlock.getInternalPropertiesId()).toBaseBlock(); + return oldBlock.toBlockState().withProperties(newBlock.toBlockState()).toBaseBlock(newBlock.getNbtData()); + } + + @Override + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + BaseBlock oldBlock = get.getFullBlock(extent); + BaseBlock newBlock = pattern.apply(get); + + BlockState oldState = oldBlock.toBlockState(); + BlockState newState = oldState.withProperties(newBlock.toBlockState()); + if (newState != oldState) { + if (oldBlock.hasNbtData()) { + set.setFullBlock(extent, newState.toBaseBlock(oldBlock.getNbtData())); + } else { + set.setBlock(extent, newState); + } + return true; + } + return false; } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/ExistingPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/ExistingPattern.java index e345a1705..35f5299c9 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/ExistingPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/ExistingPattern.java @@ -1,12 +1,10 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.block.BlockStateHolder; -import com.sk89q.worldedit.world.block.BlockTypes; public class ExistingPattern extends AbstractExtentPattern { public ExistingPattern(Extent extent) { @@ -19,10 +17,10 @@ public class ExistingPattern extends AbstractExtentPattern { } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { - if (set.equals(get)) { + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + if (set == get || set.equals(get)) { return false; } - return extent.setBlock(set, extent.getBlock(get)); + return set.setFullBlock(extent, get.getFullBlock(extent)); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/ExpressionPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/ExpressionPattern.java index aaf3ee200..36500403b 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/ExpressionPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/ExpressionPattern.java @@ -22,9 +22,7 @@ import static com.google.common.base.Preconditions.checkNotNull; * greater than {@code 0}.

*/ public class ExpressionPattern extends AbstractPattern { - - public String input; - private transient Expression expression; + private final Expression expression; /** * Create a new instance. @@ -34,7 +32,6 @@ public class ExpressionPattern extends AbstractPattern { */ public ExpressionPattern(String input) throws ExpressionException { checkNotNull(input); - this.input = input; this.expression = Expression.compile(input, "x", "y", "z"); } @@ -64,13 +61,4 @@ public class ExpressionPattern extends AbstractPattern { throw e; } } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - try { - this.expression = Expression.compile(input, "x", "y", "z"); - } catch (ExpressionException e) { - e.printStackTrace(); - } - } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/FullClipboardPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/FullClipboardPattern.java index 015eb990d..8e234a9b4 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/FullClipboardPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/FullClipboardPattern.java @@ -36,9 +36,8 @@ public class FullClipboardPattern extends AbstractExtentPattern { } @Override - public boolean apply(Extent extent, BlockVector3 setPosition, BlockVector3 getPosition) throws WorldEditException { - Region region = clipboard.getRegion(); - ForwardExtentCopy copy = new ForwardExtentCopy(clipboard, clipboard.getRegion(), clipboard.getOrigin(), extent, setPosition); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + ForwardExtentCopy copy = new ForwardExtentCopy(clipboard, clipboard.getRegion(), clipboard.getOrigin(), extent, set); copy.setSourceMask(new ExistingBlockMask(clipboard)); Operations.completeBlindly(copy); return true; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/Linear2DBlockPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/Linear2DBlockPattern.java index 2e2826525..681b96892 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/Linear2DBlockPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/Linear2DBlockPattern.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -27,11 +28,11 @@ public class Linear2DBlockPattern extends AbstractPattern { } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { int index = (get.getBlockX() + get.getBlockZ()) % patternsArray.length; if (index < 0) { index += patternsArray.length; } - return patternsArray[index].apply(extent, set, get); + return patternsArray[index].apply(extent, get, set); } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/Linear3DBlockPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/Linear3DBlockPattern.java index c52c349e9..843d07c8e 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/Linear3DBlockPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/Linear3DBlockPattern.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -27,11 +28,11 @@ public class Linear3DBlockPattern extends AbstractPattern { } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { int index = (get.getBlockX() + get.getBlockY() + get.getBlockZ()) % patternsArray.length; if (index < 0) { index += patternsArray.length; } - return patternsArray[index].apply(extent, set, get); + return patternsArray[index].apply(extent, get, set); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/LinearBlockPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/LinearBlockPattern.java index 2614dde7a..7cfd81991 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/LinearBlockPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/LinearBlockPattern.java @@ -27,11 +27,11 @@ public class LinearBlockPattern extends AbstractPattern implements ResettablePat } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { if (index == patternsArray.length) { index = 0; } - return patternsArray[index++].apply(extent, set, get); + return patternsArray[index++].apply(extent, get, set); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/MaskedPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/MaskedPattern.java index 8f9f72550..4858a92b5 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/MaskedPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/MaskedPattern.java @@ -1,5 +1,7 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; +import com.boydti.fawe.beta.SingleFilterBlock; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -12,32 +14,30 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; public class MaskedPattern extends AbstractPattern { - private final PatternExtent patternExtent; - private final Pattern secondaryPattern; + private final Pattern primary; + private final Pattern secondary; private Mask mask; - public MaskedPattern(Mask mask, PatternExtent primary, Pattern secondary) { + public MaskedPattern(Mask mask, Pattern primary, Pattern secondary) { this.mask = mask; - this.patternExtent = primary; - this.secondaryPattern = secondary; + this.primary = primary; + this.secondary = secondary; } @Override public BaseBlock apply(BlockVector3 position) { - patternExtent.setTarget(position); if (mask.test(position)) { - return patternExtent.getAndResetTarget().toBaseBlock(); + return primary.apply(position); } - return secondaryPattern.apply(position); + return secondary.apply(position); } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { - patternExtent.setTarget(get); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { if (mask.test(get)) { - return patternExtent.getAndResetTarget(extent, set, get); + return primary.apply(extent, get, set); } - return secondaryPattern.apply(extent, set, get); + return secondary.apply(extent, get, set); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/NoXPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/NoXPattern.java index 3accfc1e9..93cf0f550 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/NoXPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/NoXPattern.java @@ -1,5 +1,7 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.DelegateFilterBlock; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -15,7 +17,7 @@ import java.io.IOException; public class NoXPattern extends AbstractPattern { private final Pattern pattern; -// private transient MutableBlockVector3 mutable = new MutableBlockVector3(); + private final MutableBlockVector3 mutable = new MutableBlockVector3(); public NoXPattern(Pattern pattern) { this.pattern = pattern; @@ -23,21 +25,15 @@ public class NoXPattern extends AbstractPattern { @Override public BaseBlock apply(BlockVector3 pos) { -// mutable.mutY((pos.getY())); -// mutable.mutZ((pos.getZ())); -// return pattern.apply(mutable); - return pattern.apply(pos); + mutable.mutY((pos.getY())); + mutable.mutZ((pos.getZ())); + return pattern.apply(mutable); } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { -// mutable.mutY((get.getY())); -// mutable.mutZ((get.getZ())); - return pattern.apply(extent, set, get); - } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); -// mutable = new MutableBlockVector3(); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + mutable.mutY((get.getY())); + mutable.mutZ((get.getZ())); + return pattern.apply(extent, mutable, set); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/NoYPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/NoYPattern.java index 6c8303cff..62e4de18a 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/NoYPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/NoYPattern.java @@ -1,5 +1,7 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.DelegateFilterBlock; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -15,29 +17,23 @@ import java.io.IOException; public class NoYPattern extends AbstractPattern { private final Pattern pattern; + private final MutableBlockVector3 mutable = new MutableBlockVector3(); public NoYPattern(Pattern pattern) { this.pattern = pattern; } -// private transient MutableBlockVector3 mutable = new MutableBlockVector3(); - @Override public BaseBlock apply(BlockVector3 pos) { -// mutable.mutX((pos.getX())); -// mutable.mutZ((pos.getZ())); - return pattern.apply(pos); + mutable.mutX((pos.getX())); + mutable.mutZ((pos.getZ())); + return pattern.apply(mutable); } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { -// mutable.mutX((get.getX())); -// mutable.mutZ((get.getZ())); - return pattern.apply(extent, set, get); - } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); -// mutable = new MutableBlockVector3(); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + mutable.mutX((get.getX())); + mutable.mutZ((get.getZ())); + return pattern.apply(extent, mutable, set); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/NoZPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/NoZPattern.java index 2a4e3f362..e01894ae4 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/NoZPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/NoZPattern.java @@ -1,5 +1,7 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.DelegateFilterBlock; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -20,24 +22,19 @@ public class NoZPattern extends AbstractPattern { this.pattern = pattern; } -// private transient MutableBlockVector3 mutable = new MutableBlockVector3(); + private transient MutableBlockVector3 mutable = new MutableBlockVector3(); @Override public BaseBlock apply(BlockVector3 pos) { -// mutable.mutX((pos.getX())); -// mutable.mutY((pos.getY())); - return pattern.apply(pos); + mutable.mutX((pos.getX())); + mutable.mutY((pos.getY())); + return pattern.apply(mutable); } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { -// mutable.mutX((get.getX())); -// mutable.mutY((get.getY())); - return pattern.apply(extent, set, get); - } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); -// mutable = new MutableBlockVector3(); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + mutable.mutX((get.getX())); + mutable.mutY((get.getY())); + return pattern.apply(extent, mutable, set); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/OffsetPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/OffsetPattern.java index fd34ba1eb..bc53d1864 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/OffsetPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/OffsetPattern.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -15,7 +16,7 @@ import java.io.IOException; public class OffsetPattern extends AbstractPattern { private final int dx, dy, dz; -// private transient MutableBlockVector3 mutable = new MutableBlockVector3(); + private transient MutableBlockVector3 mutable = new MutableBlockVector3(); private final Pattern pattern; public OffsetPattern(Pattern pattern, int dx, int dy, int dz) { @@ -27,24 +28,17 @@ public class OffsetPattern extends AbstractPattern { @Override public BaseBlock apply(BlockVector3 position) { -// mutable.mutX((position.getX() + dx)); -// mutable.mutY((position.getY() + dy)); -// mutable.mutZ((position.getZ() + dz)); -// return pattern.apply(mutable); - return pattern.apply(BlockVector3.at(position.getX() + dx, position.getY() + dy, position.getZ() + dz)); + mutable.mutX((position.getX() + dx)); + mutable.mutY((position.getY() + dy)); + mutable.mutZ((position.getZ() + dz)); + return pattern.apply(mutable); } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { -// mutable.mutX((get.getX() + dx)); -// mutable.mutY((get.getY() + dy)); -// mutable.mutZ((get.getZ() + dz)); -// return pattern.apply(extent, set, mutable); - return pattern.apply(extent, set, BlockVector3.at(get.getX() + dx, get.getY() + dy, get.getZ() + dz)); - } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); -// mutable = new MutableBlockVector3(); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + mutable.mutX((get.getX() + dx)); + mutable.mutY((get.getY() + dy)); + mutable.mutZ((get.getZ() + dz)); + return pattern.apply(extent, get, mutable); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/PatternExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/PatternExtent.java deleted file mode 100644 index 534c9c694..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/PatternExtent.java +++ /dev/null @@ -1,134 +0,0 @@ -package com.boydti.fawe.object.pattern; - -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.entity.Entity; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.function.operation.Operation; -import com.sk89q.worldedit.function.pattern.AbstractPattern; -import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.math.BlockVector2; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BlockStateHolder; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import javax.annotation.Nullable; - -public class PatternExtent extends AbstractPattern implements Extent { - private final Pattern pattern; - private transient BlockStateHolder block; - private transient BlockVector3 target = BlockVector3.at(0, 0, 0); - - public PatternExtent(Pattern pattern) { - this.pattern = pattern; - } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - target = BlockVector3.at(0, 0, 0); - } - - @Override - public BlockVector3 getMinimumPoint() { - return BlockVector3.at(Integer.MIN_VALUE, 0, Integer.MIN_VALUE); - } - - @Override - public BlockVector3 getMaximumPoint() { - return BlockVector3.at(Integer.MAX_VALUE, 255, Integer.MAX_VALUE); - } - - @Override - public List getEntities(Region region) { - return new ArrayList<>(); - } - - @Override - public List getEntities() { - return new ArrayList<>(); - } - - @Nullable - @Override - public Entity createEntity(Location location, BaseEntity entity) { - return null; - } - - @Override - public BlockState getBlock(BlockVector3 position) { - BlockStateHolder tmp = pattern.apply(position); - if (position == target || (position.getX() == target.getX() && position.getY() == target.getY() && position.getZ() == target.getZ())) { - block = tmp; - } else { - block = null; - } - return (BlockState) tmp; - } - - public void setTarget(BlockVector3 vector) { - this.target = vector; - } - - public boolean getAndResetTarget(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { - BlockStateHolder result = block; - if (result != null) { - block = null; - return extent.setBlock(set, result); - } else { - return pattern.apply(extent, set, target); - } - } - - public BlockStateHolder getAndResetTarget() { - BlockStateHolder result = block; - if (result != null) { - block = null; - return result; - } else { - return pattern.apply(target); - } - } - - @Override - public BaseBlock getFullBlock(BlockVector3 position) { - return getBlock(position).toBaseBlock(); - } - - @Override - public BiomeType getBiome(BlockVector2 position) { - return null; - } - - @Override - public boolean setBlock(BlockVector3 position, BlockStateHolder block) throws WorldEditException { - return false; - } - - @Override - public boolean setBiome(BlockVector2 position, BiomeType biome) { - return false; - } - - @Nullable - @Override - public Operation commit() { - return null; - } - - @Override - public BaseBlock apply(BlockVector3 position) { - return pattern.apply(position); - } - - @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { - return pattern.apply(extent, set, get); - } -} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/PropertyPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/PropertyPattern.java index 2533017a2..cb2ee7301 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/PropertyPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/PropertyPattern.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.object.string.MutableCharSequence; import com.boydti.fawe.util.MathMan; import com.boydti.fawe.util.StringMan; @@ -14,7 +15,6 @@ import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.registry.state.PropertyKey; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; @@ -211,11 +211,11 @@ public class PropertyPattern extends AbstractExtentPattern { } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { - BaseBlock block = getExtent().getFullBlock(get); - block = apply(block, null); - if (block != null) { - return extent.setBlock(set, block); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + int ordinal = get.getOrdinal(extent); + int newOrdinal = transformed[ordinal]; + if (newOrdinal != ordinal) { + set.setOrdinal(extent, newOrdinal); } return false; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RandomFullClipboardPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RandomFullClipboardPattern.java index d49ca03ab..d58548a2c 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RandomFullClipboardPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RandomFullClipboardPattern.java @@ -12,8 +12,6 @@ import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.session.ClipboardHolder; -import java.io.IOException; -import java.io.NotSerializableException; import java.util.List; import java.util.concurrent.ThreadLocalRandom; @@ -24,18 +22,19 @@ public class RandomFullClipboardPattern extends AbstractPattern { private final Extent extent; private final MutableBlockVector3 mutable = new MutableBlockVector3(); private final List clipboards; - private boolean randomRotate; - private boolean randomFlip; + private final boolean randomRotate; + private final boolean randomFlip; public RandomFullClipboardPattern(Extent extent, List clipboards, boolean randomRotate, boolean randomFlip) { checkNotNull(clipboards); this.clipboards = clipboards; this.extent = extent; this.randomRotate = randomRotate; + this.randomFlip = randomFlip; } @Override - public boolean apply(Extent extent, BlockVector3 setPosition, BlockVector3 getPosition) throws WorldEditException { + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { ClipboardHolder holder = clipboards.get(ThreadLocalRandom.current().nextInt(clipboards.size())); AffineTransform transform = new AffineTransform(); if (randomRotate) { @@ -52,9 +51,9 @@ public class RandomFullClipboardPattern extends AbstractPattern { Schematic schematic = new Schematic(clipboard); Transform newTransform = holder.getTransform(); if (newTransform.isIdentity()) { - schematic.paste(extent, setPosition, false); + schematic.paste(extent, set, false); } else { - schematic.paste(extent, setPosition, false, newTransform); + schematic.paste(extent, set, false, newTransform); } return true; } @@ -63,8 +62,4 @@ public class RandomFullClipboardPattern extends AbstractPattern { public BaseBlock apply(BlockVector3 position) { throw new IllegalStateException("Incorrect use. This pattern can only be applied to an extent!"); } - - private void writeObject(java.io.ObjectOutputStream stream) throws IOException { - throw new NotSerializableException("Clipboard cannot be serialized!"); - } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RandomOffsetPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RandomOffsetPattern.java index 904364739..d43d2a416 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RandomOffsetPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RandomOffsetPattern.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.extent.Extent; @@ -40,19 +41,10 @@ public class RandomOffsetPattern extends AbstractPattern { } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { - mutable.mutX((get.getX() + r.nextInt(dx2) - dx)); - mutable.mutY((get.getY() + r.nextInt(dy2) - dy)); - mutable.mutZ((get.getZ() + r.nextInt(dz2) - dz)); - return pattern.apply(extent, set, mutable); - } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - this.dx2 = dx * 2 + 1; - this.dy2 = dy * 2 + 1; - this.dz2 = dz * 2 + 1; - this.r = new SplittableRandom(); - this.mutable = new MutableBlockVector3(); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + mutable.mutX((set.getX() + r.nextInt(dx2) - dx)); + mutable.mutY((set.getY() + r.nextInt(dy2) - dy)); + mutable.mutZ((set.getZ() + r.nextInt(dz2) - dz)); + return pattern.apply(extent, get, mutable); } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RelativePattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RelativePattern.java index e8f3f56ea..4900a5317 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RelativePattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RelativePattern.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.extent.Extent; @@ -13,8 +14,8 @@ import java.io.IOException; public class RelativePattern extends AbstractPattern implements ResettablePattern { private final Pattern pattern; - private transient BlockVector3 origin; - private transient MutableBlockVector3 mutable = new MutableBlockVector3(); + private BlockVector3 origin; + private final MutableBlockVector3 mutable = new MutableBlockVector3(); public RelativePattern(Pattern pattern) { this.pattern = pattern; @@ -32,19 +33,14 @@ public class RelativePattern extends AbstractPattern implements ResettablePatter } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { if (origin == null) { - origin = get; + origin = set; } - mutable.mutX((get.getX() - origin.getX())); - mutable.mutY((get.getY() - origin.getY())); - mutable.mutZ((get.getZ() - origin.getZ())); - return pattern.apply(extent, set, mutable); - } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - mutable = new MutableBlockVector3(); + mutable.mutX((set.getX() - origin.getX())); + mutable.mutY((set.getY() - origin.getY())); + mutable.mutZ((set.getZ() - origin.getZ())); + return pattern.apply(extent, get, mutable); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/SolidRandomOffsetPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/SolidRandomOffsetPattern.java index 3ac516bc7..b5ab2fd4c 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/SolidRandomOffsetPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/SolidRandomOffsetPattern.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.extent.Extent; @@ -9,6 +10,8 @@ import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; import java.io.IOException; import java.util.SplittableRandom; @@ -17,25 +20,27 @@ public class SolidRandomOffsetPattern extends AbstractPattern { private final int dx, dy, dz; private final Pattern pattern; - private transient int dx2, dy2, dz2; - private transient MutableBlockVector3 mutable; - private transient boolean[] solid; + private final int dx2, dy2, dz2; + private final MutableBlockVector3 mutable; private SplittableRandom r; + public static boolean[] getTypes() { + boolean[] types = new boolean[BlockTypes.size()]; + for (BlockType type : BlockTypes.values) { + types[type.getInternalId()] = type.getMaterial().isSolid(); + } + return types; + } public SolidRandomOffsetPattern(Pattern pattern, int dx, int dy, int dz) { this.pattern = pattern; this.dx = dx; this.dy = dy; this.dz = dz; - init(); - } - private void init() { this.dx2 = dx * 2 + 1; this.dy2 = dy * 2 + 1; this.dz2 = dz * 2 + 1; - solid = SolidBlockMask.getTypes(); this.r = new SplittableRandom(); this.mutable = new MutableBlockVector3(); } @@ -46,7 +51,7 @@ public class SolidRandomOffsetPattern extends AbstractPattern { mutable.mutY((position.getY() + r.nextInt(dy2) - dy)); mutable.mutZ((position.getZ() + r.nextInt(dz2) - dz)); BaseBlock block = pattern.apply(mutable); - if (solid[block.getInternalBlockTypeId()]) { + if (block.getMaterial().isSolid()) { return block; } else { return pattern.apply(position); @@ -54,20 +59,15 @@ public class SolidRandomOffsetPattern extends AbstractPattern { } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { - mutable.mutX((get.getX() + r.nextInt(dx2) - dx)); - mutable.mutY((get.getY() + r.nextInt(dy2) - dy)); - mutable.mutZ((get.getZ() + r.nextInt(dz2) - dz)); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + mutable.mutX((set.getX() + r.nextInt(dx2) - dx)); + mutable.mutY((set.getY() + r.nextInt(dy2) - dy)); + mutable.mutZ((set.getZ() + r.nextInt(dz2) - dz)); BlockStateHolder block = pattern.apply(mutable); - if (solid[block.getInternalBlockTypeId()]) { - return pattern.apply(extent, set, mutable); + if (block.getMaterial().isSolid()) { + return pattern.apply(extent, get, mutable); } else { - return pattern.apply(extent, set, get); + return pattern.apply(extent, get, set); } } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - init(); - } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/SurfaceRandomOffsetPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/SurfaceRandomOffsetPattern.java index 9a9df9241..03ee435a0 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/SurfaceRandomOffsetPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/SurfaceRandomOffsetPattern.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.function.pattern.AbstractPattern; import com.sk89q.worldedit.function.pattern.Pattern; @@ -13,19 +14,16 @@ import java.util.concurrent.ThreadLocalRandom; public class SurfaceRandomOffsetPattern extends AbstractPattern { private final Pattern pattern; - private int moves; + private final int moves; - private transient MutableBlockVector3 cur; - private transient MutableBlockVector3[] buffer; - private transient MutableBlockVector3[] allowed; + private final MutableBlockVector3 cur; + private final MutableBlockVector3[] buffer; + private final MutableBlockVector3[] allowed; + private MutableBlockVector3 next; public SurfaceRandomOffsetPattern(Pattern pattern, int distance) { this.pattern = pattern; this.moves = Math.min(255, distance); - init(); - } - - private void init() { cur = new MutableBlockVector3(); this.buffer = new MutableBlockVector3[BreadthFirstSearch.DIAGONAL_DIRECTIONS.length]; for (int i = 0; i < buffer.length; i++) { @@ -110,9 +108,4 @@ public class SurfaceRandomOffsetPattern extends AbstractPattern { BlockStateHolder block = pattern.apply(v); return !block.getBlockType().getMaterial().isMovementBlocker(); } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - init(); - } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/progress/ChatProgressTracker.java b/worldedit-core/src/main/java/com/boydti/fawe/object/progress/ChatProgressTracker.java index 1c6b3a908..ae2fcf752 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/progress/ChatProgressTracker.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/progress/ChatProgressTracker.java @@ -9,18 +9,8 @@ public class ChatProgressTracker extends DefaultProgressTracker { setInterval(getDelay() / 50); } - @Override - public void sendTask() { - super.sendTask(); - } - - @Override - public void doneTask() { - super.doneTask(); - } - @Override public void sendTile(String title, String sub) { getPlayer().sendMessage(BBC.getPrefix() + title + sub); } -} \ No newline at end of file +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/queue/FaweQueueDelegateExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/queue/FaweQueueDelegateExtent.java index 0eed3a025..db0c437fe 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/queue/FaweQueueDelegateExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/queue/FaweQueueDelegateExtent.java @@ -49,7 +49,7 @@ public class FaweQueueDelegateExtent extends DelegateFaweQueue { @Override public int getCombinedId4Data(int x, int y, int z) throws FaweException.FaweChunkLoadException { - return getLazyBlock(x, y, z).getInternalId(); + return getBlock(x, y, z).getInternalId(); } @Override @@ -86,16 +86,4 @@ public class FaweQueueDelegateExtent extends DelegateFaweQueue { public boolean setBlock(int x, int y, int z, BlockStateHolder block) throws WorldEditException { return parentExtent.setBlock(x, y, z, block); } - - @Override - public BlockState getLazyBlock(BlockVector3 position) { - return parentExtent.getLazyBlock(position); - } - - @Override - public BlockState getLazyBlock(int x, int y, int z) { - return parentExtent.getLazyBlock(x, y, z); - } - - } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/queue/IDelegateFaweQueue.java b/worldedit-core/src/main/java/com/boydti/fawe/object/queue/IDelegateFaweQueue.java index aeee48c7b..a7529b482 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/queue/IDelegateFaweQueue.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/queue/IDelegateFaweQueue.java @@ -62,8 +62,8 @@ public interface IDelegateFaweQueue extends FaweQueue { } @Override - default BlockState getLazyBlock(int x, int y, int z) { - return getQueue().getLazyBlock(x, y, z); + default BlockState getBlock(int x, int y, int z) { + return getQueue().getBlock(x, y, z); } @Override @@ -454,11 +454,6 @@ public interface IDelegateFaweQueue extends FaweQueue { return getQueue().createEntity(location, entity); } - @Override - default BlockState getLazyBlock(BlockVector3 position) { - return getQueue().getLazyBlock(position); - } - @Nullable @Override default Operation commit() { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/regions/FuzzyRegion.java b/worldedit-core/src/main/java/com/boydti/fawe/object/regions/FuzzyRegion.java index e9064b62b..f03cedcc0 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/regions/FuzzyRegion.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/regions/FuzzyRegion.java @@ -1,6 +1,5 @@ package com.boydti.fawe.object.regions; -import com.boydti.fawe.object.HasFaweQueue; import com.boydti.fawe.object.collection.BlockVectorSet; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEditException; @@ -19,10 +18,8 @@ public class FuzzyRegion extends AbstractRegion { private final Mask mask; private BlockVectorSet set = new BlockVectorSet(); - private boolean populated; private int minX, minY, minZ, maxX, maxY, maxZ; private Extent extent; - private int count = 0; { minX = minY = minZ = Integer.MAX_VALUE; @@ -51,7 +48,7 @@ public class FuzzyRegion extends AbstractRegion { setMinMax(p.getBlockX(), p.getBlockY(), p.getBlockZ()); return true; } - }, 256, extent instanceof HasFaweQueue ? (HasFaweQueue) extent : null); + }, 256); search.setVisited(set); search.visit(BlockVector3.at(x, y, z)); Operations.completeBlindly(search); @@ -59,7 +56,7 @@ public class FuzzyRegion extends AbstractRegion { @Override public Iterator iterator() { - return (Iterator) set.iterator(); + return set.iterator(); } private final void setMinMax(int x, int y, int z) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/regions/PolyhedralRegion.java b/worldedit-core/src/main/java/com/boydti/fawe/object/regions/PolyhedralRegion.java index 28ec2681b..0df9a9594 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/regions/PolyhedralRegion.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/regions/PolyhedralRegion.java @@ -159,7 +159,7 @@ public class PolyhedralRegion extends AbstractRegion { case 3: // Generate minimal mesh to start from - final BlockVector3[] v = vertices.toArray(new BlockVector3[vertices.size()]); + final BlockVector3[] v = vertices.toArray(new BlockVector3[0]); triangles.add((new Triangle(v[0], v[size - 2], v[size - 1]))); triangles.add((new Triangle(v[0], v[size - 1], v[size - 2]))); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/schematic/StructureFormat.java b/worldedit-core/src/main/java/com/boydti/fawe/object/schematic/MinecraftStructure.java similarity index 92% rename from worldedit-core/src/main/java/com/boydti/fawe/object/schematic/StructureFormat.java rename to worldedit-core/src/main/java/com/boydti/fawe/object/schematic/MinecraftStructure.java index 89838bad3..6029d2b85 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/schematic/StructureFormat.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/schematic/MinecraftStructure.java @@ -3,18 +3,8 @@ package com.boydti.fawe.object.schematic; import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweCache; import com.boydti.fawe.util.ReflectionUtils; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.DoubleTag; -import com.sk89q.jnbt.FloatTag; -import com.sk89q.jnbt.IntTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.NBTInputStream; -import com.sk89q.jnbt.NBTOutputStream; -import com.sk89q.jnbt.NamedTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; + +import com.sk89q.jnbt.*; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; @@ -28,14 +18,15 @@ import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.registry.state.AbstractProperty; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; -import com.sk89q.worldedit.world.registry.BundledBlockData; import com.sk89q.worldedit.world.storage.NBTConversions; import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; +import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.util.ArrayList; @@ -45,17 +36,17 @@ import java.util.List; import java.util.Map; import java.util.UUID; -public class StructureFormat implements ClipboardReader, ClipboardWriter { +public class MinecraftStructure implements ClipboardReader, ClipboardWriter { private static final int WARN_SIZE = 32; - private NBTInputStream in; + private NBTInputStream inputStream; private NBTOutputStream out; - public StructureFormat(NBTInputStream in) { - this.in = in; + public MinecraftStructure(@NotNull NBTInputStream inputStream) { + this.inputStream = inputStream; } - public StructureFormat(NBTOutputStream out) { + public MinecraftStructure(NBTOutputStream out) { this.out = out; } @@ -65,10 +56,13 @@ public class StructureFormat implements ClipboardReader, ClipboardWriter { } public Clipboard read(UUID clipboardId) throws IOException { - NamedTag rootTag = in.readNamedTag(); - if (!rootTag.getName().equals("")) { - throw new IOException("Root tag does not exist or is not first"); + NamedTag rootTag = inputStream.readNamedTag(); + + // MC structures are all unnamed, but this doesn't seem to be necessary? might remove this later + if (!rootTag.getName().isEmpty()) { + throw new IOException("Root tag has name - are you sure this is a structure?"); } + Map tags = ((CompoundTag) rootTag.getTag()).getValue(); ListTag size = (ListTag) tags.get("size"); @@ -258,8 +252,8 @@ public class StructureFormat implements ClipboardReader, ClipboardWriter { @Override public void close() throws IOException { - if (in != null) { - in.close(); + if (inputStream != null) { + inputStream.close(); } if (out != null) { out.close(); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/schematic/Schematic.java b/worldedit-core/src/main/java/com/boydti/fawe/object/schematic/Schematic.java index 464465b5d..2f0a93b29 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/schematic/Schematic.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/schematic/Schematic.java @@ -122,7 +122,6 @@ public class Schematic { public EditSession paste(World world, BlockVector3 to, boolean allowUndo, boolean pasteAir, boolean copyEntities, @Nullable Transform transform) { checkNotNull(world); checkNotNull(to); - Region region = clipboard.getRegion(); EditSession editSession; if (world instanceof EditSession) { editSession = (EditSession) world; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/schematic/visualizer/SchemVis.java b/worldedit-core/src/main/java/com/boydti/fawe/object/schematic/visualizer/SchemVis.java index cf393791c..5755c9aa2 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/schematic/visualizer/SchemVis.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/schematic/visualizer/SchemVis.java @@ -551,13 +551,13 @@ // public void sendChunk(int x, int z, int bitMask) { /* do nothing - never used*/ } // // @Override -// public BiomeType getBiomeType(int x, int z) throws FaweException.FaweChunkLoadException { +// public BiomeType getBiomeType(int x, int z) throws FaweException.CHUNK { // // TODO later (currently not used) // return BiomeTypes.FOREST; // } // // @Override -// public int getCombinedId4Data(int x, int y, int z) throws FaweException.FaweChunkLoadException { +// public int getCombinedId4Data(int x, int y, int z) throws FaweException.CHUNK { // MCAChunk chunk = getChunk(x >> 4, z >> 4); // if (y < 0 || y > 255) return 0; // return chunk.getBlockCombinedId(x & 15, y, z & 15); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/visitor/AboveVisitor.java b/worldedit-core/src/main/java/com/boydti/fawe/object/visitor/AboveVisitor.java index 71de953b1..5fdd439c8 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/visitor/AboveVisitor.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/visitor/AboveVisitor.java @@ -6,6 +6,7 @@ import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.visitor.RecursiveVisitor; import com.sk89q.worldedit.math.BlockVector3; +import java.util.Arrays; import java.util.Collection; @@ -39,14 +40,14 @@ public class AboveVisitor extends RecursiveVisitor { this.baseY = baseY; - Collection directions = getDirections(); - directions.clear(); - directions.add(BlockVector3.at(1, 0, 0)); - directions.add(BlockVector3.at(-1, 0, 0)); - directions.add(BlockVector3.at(0, 0, 1)); - directions.add(BlockVector3.at(0, 0, -1)); - directions.add(BlockVector3.at(0, 1, 0)); - directions.add(BlockVector3.at(0, -1, 0)); + setDirections( + BlockVector3.UNIT_MINUS_X, + BlockVector3.UNIT_MINUS_Y, + BlockVector3.UNIT_MINUS_Z, + BlockVector3.UNIT_X, + BlockVector3.UNIT_Y, + BlockVector3.UNIT_Z + ); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/visitor/FaweChunkVisitor.java b/worldedit-core/src/main/java/com/boydti/fawe/object/visitor/FaweChunkVisitor.java index 07e0cbdc5..33a535303 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/visitor/FaweChunkVisitor.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/visitor/FaweChunkVisitor.java @@ -1,13 +1,13 @@ package com.boydti.fawe.object.visitor; -public abstract class FaweChunkVisitor { +public interface FaweChunkVisitor { /** * The will run for each set block in the chunk * - * @param localX The x position in the chunk (0-15) - * @param y The y position (0 - 255) - * @param localZ The z position in the chunk (0-15) + * @param localX The x position in the chunk (0-15) + * @param y The y position (0 - 255) + * @param localZ The z position in the chunk (0-15) * @param combined The combined id */ - public abstract void run(int localX, int y, int localZ, int combined); + void run(int localX, int y, int localZ, int combined); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/regions/general/plot/PlotTrim.java b/worldedit-core/src/main/java/com/boydti/fawe/regions/general/plot/PlotTrim.java index 2bb7aa619..c859b84ca 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/regions/general/plot/PlotTrim.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/regions/general/plot/PlotTrim.java @@ -8,6 +8,7 @@ import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.MathMan; import com.boydti.fawe.util.SetQueue; + import com.github.intellectualsites.plotsquared.plot.PlotSquared; import com.github.intellectualsites.plotsquared.plot.object.ChunkLoc; import com.github.intellectualsites.plotsquared.plot.object.Location; @@ -15,6 +16,7 @@ import com.github.intellectualsites.plotsquared.plot.object.Plot; import com.github.intellectualsites.plotsquared.plot.object.PlotArea; import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; import com.github.intellectualsites.plotsquared.plot.util.expiry.ExpireManager; +import static com.google.common.base.Preconditions.checkNotNull; import com.sk89q.worldedit.world.block.BlockTypes; import java.io.File; @@ -26,25 +28,20 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; - -import static com.google.common.base.Preconditions.checkNotNull; - public class PlotTrim { private final MCAQueue queue; private final PlotArea area; private final PlotPlayer player; private final MCAQueue originalQueue; private final File root; - private final File originalRoot; private int[][] ids; - private boolean deleteUnowned = true; + private boolean deleteUnowned; public PlotTrim(PlotPlayer player, PlotArea area, String worldName, boolean deleteUnowned) { FaweQueue tmpQueue = SetQueue.IMP.getNewQueue(worldName, true, false); File saveFolder = tmpQueue.getSaveFolder(); this.root = new File(saveFolder.getParentFile().getParentFile(), worldName + "-Copy" + File.separator + "region"); - this.originalRoot = saveFolder; - this.originalQueue = new MCAQueue(worldName, originalRoot, true); + this.originalQueue = new MCAQueue(worldName, saveFolder, true); this.queue = new MCAQueue(worldName + "-Copy", root, true); this.area = area; this.player = player; @@ -124,10 +121,7 @@ public class PlotTrim { @Override public boolean appliesFile(int mcaX, int mcaZ) { ChunkLoc loc = new ChunkLoc(mcaX, mcaZ); - if (mcas.contains(loc)) { - return false; - } - return true; + return !mcas.contains(loc); } @Override @@ -155,11 +149,6 @@ public class PlotTrim { } } - @Override - public boolean appliesChunk(int cx, int cz) { - return true; - } - @Override public MCAChunk applyChunk(MCAChunk chunk, Object ignore) { long pair = MathMan.pairInt(chunk.getX(), chunk.getZ()); @@ -181,8 +170,6 @@ public class PlotTrim { player.sendMessage("Done!"); } - private int count = 0; - private boolean isEqual(int[] a, int[] b) { if (a == b) { return true; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/IncendoPaster.java b/worldedit-core/src/main/java/com/boydti/fawe/util/IncendoPaster.java index 86a415298..7c9128453 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/IncendoPaster.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/IncendoPaster.java @@ -43,7 +43,7 @@ public final class IncendoPaster { if (pasteApplication == null || pasteApplication.isEmpty()) { throw new IllegalArgumentException("paste application cannot be null, nor empty"); } - if (!VALID_APPLICATIONS.contains(pasteApplication.toLowerCase(Locale.ENGLISH))) { + if (!VALID_APPLICATIONS.contains(pasteApplication.toLowerCase(Locale.ROOT))) { throw new IllegalArgumentException( String.format("Unknown application name: %s", pasteApplication)); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java b/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java index 36de2fbc3..e978949e9 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java @@ -1,15 +1,14 @@ package com.boydti.fawe.util; import com.boydti.fawe.Fawe; +import com.boydti.fawe.beta.SingleFilterBlock; import com.boydti.fawe.config.Settings; -import com.boydti.fawe.object.pattern.PatternExtent; import com.boydti.fawe.util.image.ImageUtil; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.mask.Mask; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; @@ -66,14 +65,15 @@ public class TextureUtil implements TextureHolder { public static TextureUtil fromMask(Mask mask) throws FileNotFoundException { HashSet blocks = new HashSet<>(); - BlockPattern pattern = new BlockPattern(BlockTypes.AIR.getDefaultState()); - PatternExtent extent = new PatternExtent(pattern); + + SingleFilterBlock extent = new SingleFilterBlock(); new MaskTraverser(mask).reset(extent); + TextureUtil tu = Fawe.get().getTextureUtil(); for (int typeId : tu.getValidBlockIds()) { BlockType block = BlockTypes.get(typeId); - pattern.setBlock(block.getDefaultState()); - if (mask.test(BlockVector3.ZERO)) { + extent.init(0, 0, 0, block.getDefaultState().toBaseBlock()); + if (mask.test(extent)) { blocks.add(block); } } @@ -491,7 +491,7 @@ public class TextureUtil implements TextureHolder { BlockType block = getNearestBlock(color); TextureUtil.BiomeColor biome = getNearestBiome(color); int blockColor = getColor(block); - blockAndBiomeIdOutput[0] = block.getInternalId(); + blockAndBiomeIdOutput[0] = block.getDefaultState().getOrdinalChar(); blockAndBiomeIdOutput[1] = biome.id; if (colorDistance(biome.grassCombined, color) - biomePriority > colorDistance(blockColor, color)) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/WEManager.java b/worldedit-core/src/main/java/com/boydti/fawe/util/WEManager.java index 7d08000be..878a18b7b 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/WEManager.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/WEManager.java @@ -24,7 +24,7 @@ public class WEManager { public final ArrayDeque managers = new ArrayDeque<>(); - public void cancelEditSafe(Extent parent, BBC reason) throws FaweException { + public void cancelEditSafe(Extent parent, FaweException reason) throws FaweException { try { final Field field = AbstractDelegateExtent.class.getDeclaredField("extent"); field.setAccessible(true); @@ -35,10 +35,10 @@ public class WEManager { } catch (final Exception e) { e.printStackTrace(); } - throw new FaweException(reason); + throw reason; } - public void cancelEdit(Extent parent, BBC reason) throws WorldEditException { + public void cancelEdit(Extent parent, FaweException reason) throws WorldEditException { cancelEditSafe(parent, reason); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/web/SchemSync.java b/worldedit-core/src/main/java/com/boydti/fawe/web/SchemSync.java index 7ef61dde1..240d32097 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/web/SchemSync.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/web/SchemSync.java @@ -53,7 +53,7 @@ public class SchemSync implements Runnable { private void close(Error error) throws IOException { this.clientSocket.getOutputStream().write(error.ordinal()); - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MANUAL); + throw FaweException.MANUAL; } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/wrappers/WorldWrapper.java b/worldedit-core/src/main/java/com/boydti/fawe/wrappers/WorldWrapper.java index 4f111f826..d90d93b1d 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/wrappers/WorldWrapper.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/wrappers/WorldWrapper.java @@ -2,7 +2,10 @@ package com.boydti.fawe.wrappers; import com.boydti.fawe.object.RunnableVal; import com.boydti.fawe.util.TaskManager; -import com.sk89q.worldedit.*; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.entity.BaseEntity; @@ -28,7 +31,6 @@ import com.sk89q.worldedit.world.weather.WeatherType; import javax.annotation.Nullable; import java.util.List; -import java.util.function.Supplier; public class WorldWrapper extends AbstractWorld { @@ -99,7 +101,7 @@ public class WorldWrapper extends AbstractWorld { @Override public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, BlockVector3 position) throws MaxChangedBlocksException { - return TaskManager.IMP.sync((Supplier) () -> { + return TaskManager.IMP.sync(() -> { try { return parent.generateTree(type, editSession, position); } catch (MaxChangedBlocksException e) { @@ -235,11 +237,6 @@ public class WorldWrapper extends AbstractWorld { return parent.getBlock(position); } - @Override - public BlockState getLazyBlock(BlockVector3 position) { - return parent.getLazyBlock(position); - } - @Override public BaseBlock getFullBlock(BlockVector3 position) { return parent.getFullBlock(position); diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java index 04649bd5f..a12e58d69 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java @@ -424,6 +424,16 @@ public class CompoundTag extends Tag { } } + @Override + public Map toRaw() { + HashMap raw = new HashMap<>(); + if (this.value.isEmpty()) return raw; + for (Map.Entry entry : value.entrySet()) { + raw.put(entry.getKey(), entry.getValue().toRaw()); + } + return raw; + } + @Override public String toString() { StringBuilder bldr = new StringBuilder(); diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/ListTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/ListTag.java index e29da1c0a..42732d92a 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/ListTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ListTag.java @@ -21,6 +21,7 @@ package com.sk89q.jnbt; import static com.google.common.base.Preconditions.checkNotNull; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -416,6 +417,18 @@ public final class ListTag extends Tag { } } + @Override + public ArrayList toRaw() { + ArrayList raw = new ArrayList<>(); + if (this.value.isEmpty()) { + return raw; + } + for (Tag elem : this.value) { + raw.add(elem.toRaw()); + } + return raw; + } + @Override public String toString() { StringBuilder bldr = new StringBuilder(); diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java index 47d501f09..d7c273b17 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java @@ -31,4 +31,8 @@ public abstract class Tag { */ public abstract Object getValue(); + public Object toRaw() { + return getValue(); + } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/TileEntityBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/TileEntityBlock.java index 3c67bf0e8..c193e5f4c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/TileEntityBlock.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/TileEntityBlock.java @@ -19,6 +19,9 @@ package com.sk89q.worldedit.blocks; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.world.NbtValued; /** @@ -34,6 +37,17 @@ public interface TileEntityBlock extends NbtValued { * * @return tile entity ID, non-null string */ - String getNbtId(); + default String getNbtId() { + CompoundTag nbtData = getNbtData(); + if (nbtData == null) { + return ""; + } + Tag idTag = nbtData.getValue().get("id"); + if (idTag instanceof StringTag) { + return ((StringTag) idTag).getValue(); + } else { + return ""; + } + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java index dc2eceec0..620fa50c1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java @@ -68,7 +68,7 @@ public class AreaPickaxe implements BlockTool { for (int x = ox - range; x <= ox + range; ++x) { for (int z = oz - range; z <= oz + range; ++z) { for (int y = oy + range; y >= oy - range; --y) { - if (editSession.getLazyBlock(x, y, z).getBlockType() != initialType) { + if (initialType.equals(editSession.getBlock(x, y, z))) { continue; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java index c7c5edf0e..7b4cd9995 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java @@ -66,7 +66,6 @@ public class EditSessionEvent extends Event implements Cancellable { private final int maxBlocks; private final Stage stage; private Extent extent; - private EditSession session; private boolean cancelled; /** @@ -84,14 +83,6 @@ public class EditSessionEvent extends Event implements Cancellable { this.stage = stage; } - public void setEditSession(EditSession session) { - this.session = session; - } - - public EditSession getEditSession() { - return session; - } - /** * Get the actor for this event. * @@ -165,9 +156,7 @@ public class EditSessionEvent extends Event implements Cancellable { * @return a new event */ public EditSessionEvent clone(Stage stage) { - EditSessionEvent clone = new EditSessionEvent(world, actor, maxBlocks, stage); - clone.setEditSession(session); - return clone; + return new EditSessionEvent(world, actor, maxBlocks, stage); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java index d00d1136f..d750ff860 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java @@ -21,12 +21,7 @@ package com.sk89q.worldedit.extension.factory; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.factory.parser.pattern.BlockCategoryPatternParser; -import com.sk89q.worldedit.extension.factory.parser.pattern.ClipboardPatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.DefaultPatternParser; -import com.sk89q.worldedit.extension.factory.parser.pattern.RandomPatternParser; -import com.sk89q.worldedit.extension.factory.parser.pattern.RandomStatePatternParser; -import com.sk89q.worldedit.extension.factory.parser.pattern.SingleBlockPatternParser; -import com.sk89q.worldedit.extension.factory.parser.pattern.TypeOrStateApplyingPatternParser; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.internal.registry.AbstractFactory; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/DefaultPatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/DefaultPatternParser.java index 5e19a370d..f26231194 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/DefaultPatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/DefaultPatternParser.java @@ -43,6 +43,7 @@ import com.sk89q.worldedit.util.command.parametric.ParametricBuilder; import com.sk89q.worldedit.world.block.BlockTypes; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -101,7 +102,7 @@ public class DefaultPatternParser extends FaweParser { () -> { if (full.length() == 1) return new ArrayList<>(dispatcher.getPrimaryAliases()); return dispatcher.getAliases().stream().filter( - s -> s.startsWith(command.toLowerCase()) + s -> s.startsWith(command.toLowerCase(Locale.ROOT)) ).collect(Collectors.toList()); } ); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java index 1c3d2d33a..c4059a4fe 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java @@ -24,24 +24,34 @@ import com.boydti.fawe.jnbt.anvil.generator.GenBase; import com.boydti.fawe.jnbt.anvil.generator.OreGen; import com.boydti.fawe.jnbt.anvil.generator.Resource; import com.boydti.fawe.jnbt.anvil.generator.SchemGen; - import com.boydti.fawe.object.clipboard.WorldCopyClipboard; +import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.function.RegionMaskingFilter; +import com.sk89q.worldedit.function.block.BlockReplace; +import com.sk89q.worldedit.function.mask.BlockMask; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.function.visitor.RegionVisitor; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.MathUtils; import com.sk89q.worldedit.math.MutableBlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.registry.state.PropertyGroup; import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; @@ -51,8 +61,11 @@ import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.concurrent.ThreadLocalRandom; +import static com.google.common.base.Preconditions.checkNotNull; + /** * A world, portion of a world, clipboard, or other object that can have blocks * set or entities placed. @@ -120,33 +133,11 @@ public interface Extent extends InputExtent, OutputExtent { return null; } - @Override - default BlockState getBlock(BlockVector3 position) { - return getFullBlock(position).toImmutableState(); - } - - @Override - default BlockState getLazyBlock(BlockVector3 position) { - return getFullBlock(position).toImmutableState(); - } - - default BlockState getLazyBlock(int x, int y, int z) { - return getLazyBlock(BlockVector3.at(x, y, z)); - } - - default > boolean setBlock(int x, int y, int z, T state) throws WorldEditException { - return setBlock(BlockVector3.at(x, y, z), state); - } - - default boolean setBiome(int x, int y, int z, BiomeType biome) { - return setBiome(BlockVector2.at(x, z), biome); - } - default int getHighestTerrainBlock(final int x, final int z, int minY, int maxY) { maxY = Math.min(maxY, Math.max(0, maxY)); minY = Math.max(0, minY); for (int y = maxY; y >= minY; --y) { - BlockState block = getLazyBlock(x, y, z); + BlockState block = getBlock(x, y, z); if (block.getBlockType().getMaterial().isMovementBlocker()) { return y; } @@ -170,20 +161,20 @@ public interface Extent extends InputExtent, OutputExtent { int clearanceBelow = y - minY; int clearance = Math.min(clearanceAbove, clearanceBelow); - BlockState block = getLazyBlock(x, y, z); + BlockState block = getBlock(x, y, z); boolean state = !block.getBlockType().getMaterial().isMovementBlocker(); int data1 = PropertyGroup.LEVEL.get(block); int data2 = data1; int offset = state ? 0 : 1; for (int d = 0; d <= clearance; d++) { int y1 = y + d; - block = getLazyBlock(x, y1, z); + block = getBlock(x, y1, z); if (block.getBlockType().getMaterial().isMovementBlocker() == state) { return ((y1 - offset) << 4) - (15 - (state ? PropertyGroup.LEVEL.get(block) : data1)); } data1 = PropertyGroup.LEVEL.get(block); int y2 = y - d; - block = getLazyBlock(x, y2, z); + block = getBlock(x, y2, z); if (block.getBlockType().getMaterial().isMovementBlocker() == state) { return ((y2 + offset) << 4) - (15 - (state ? PropertyGroup.LEVEL.get(block) : data2)); } @@ -192,15 +183,15 @@ public interface Extent extends InputExtent, OutputExtent { if (clearanceAbove != clearanceBelow) { if (clearanceAbove < clearanceBelow) { for (int layer = y - clearance - 1; layer >= minY; layer--) { - block = getLazyBlock(x, layer, z); + block = getBlock(x, layer, z); if (block.getBlockType().getMaterial().isMovementBlocker() == state) { - return layer + offset << 4; + return ((layer + offset) << 4) + 0; } data1 = PropertyGroup.LEVEL.get(block); } } else { for (int layer = y + clearance + 1; layer <= maxY; layer++) { - block = getLazyBlock(x, layer, z); + block = getBlock(x, layer, z); if (block.getBlockType().getMaterial().isMovementBlocker() == state) { return ((layer - offset) << 4) - (15 - (state ? PropertyGroup.LEVEL.get(block) : data2)); } @@ -255,33 +246,33 @@ public interface Extent extends InputExtent, OutputExtent { int clearanceAbove = maxY - y; int clearanceBelow = y - minY; int clearance = Math.min(clearanceAbove, clearanceBelow); - BlockStateHolder block = getLazyBlock(x, y, z); + BlockStateHolder block = getBlock(x, y, z); boolean state = !block.getBlockType().getMaterial().isMovementBlocker(); int offset = state ? 0 : 1; for (int d = 0; d <= clearance; d++) { int y1 = y + d; - block = getLazyBlock(x, y1, z); + block = getBlock(x, y1, z); if (block.getMaterial().isMovementBlocker() == state && block.getBlockType() != BlockTypes.__RESERVED__) return y1 - offset; int y2 = y - d; - block = getLazyBlock(x, y2, z); + block = getBlock(x, y2, z); if (block.getMaterial().isMovementBlocker() == state && block.getBlockType() != BlockTypes.__RESERVED__) return y2 + offset; } if (clearanceAbove != clearanceBelow) { if (clearanceAbove < clearanceBelow) { for (int layer = y - clearance - 1; layer >= minY; layer--) { - block = getLazyBlock(x, layer, z); + block = getBlock(x, layer, z); if (block.getMaterial().isMovementBlocker() == state && block.getBlockType() != BlockTypes.__RESERVED__) return layer + offset; } } else { for (int layer = y + clearance + 1; layer <= maxY; layer++) { - block = getLazyBlock(x, layer, z); + block = getBlock(x, layer, z); if (block.getMaterial().isMovementBlocker() == state && block.getBlockType() != BlockTypes.__RESERVED__) return layer - offset; } } } int result = state ? failedMin : failedMax; if(result > 0 && !ignoreAir) { - block = getLazyBlock(x, result, z); + block = getBlock(x, result, z); return block.getBlockType().getMaterial().isAir() ? -1 : result; } return result; @@ -407,6 +398,10 @@ public interface Extent extends InputExtent, OutputExtent { return null; } + default boolean cancel() { + return true; + } + default int getMaxY() { return 255; } @@ -423,4 +418,169 @@ public interface Extent extends InputExtent, OutputExtent { weClipboard.setOrigin(region.getMinimumPoint()); return weClipboard; } + + + /** + * 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 block + */ + default int countBlocks(Region region, Set searchBlocks) { + BlockMask mask = new BlockMask(this, searchBlocks); + return countBlocks(region, mask); + } + + /** + * Count the number of blocks of a list of types in a region. + * + * @param region the region + * @param searchMask mask to match + * @return the number of blocks that matched the mask + */ + default int countBlocks(Region region, Mask searchMask) { + RegionVisitor visitor = new RegionVisitor(region, searchMask::test); + Operations.completeBlindly(visitor); + return visitor.getAffected(); + } + + /** + * 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 + */ + default > int setBlocks(Region region, B block) throws MaxChangedBlocksException { + checkNotNull(region); + checkNotNull(block); + boolean hasNbt = block instanceof BaseBlock && ((BaseBlock)block).hasNbtData(); + + if (canBypassAll(region, false, true) && !hasNbt) { + return changes = queue.setBlocks((CuboidRegion) region, block.getInternalId()); + } + try { + if (hasExtraExtents()) { + RegionVisitor visitor = new RegionVisitor(region, new BlockReplace(getExtent(), (block)), this); + Operations.completeBlindly(visitor); + this.changes += visitor.getAffected(); + } else { + for (BlockVector3 blockVector3 : region) { + if (getExtent().setBlock(blockVector3, block)) { + changes++; + } + } + } + } catch (final WorldEditException e) { + throw new RuntimeException("Unexpected exception", e); + } + return changes; + } + + /** + * 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 + */ + default int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException { + checkNotNull(region); + checkNotNull(pattern); + if (pattern instanceof BlockPattern) { + return setBlocks(region, ((BlockPattern) pattern).getBlock()); + } + if (pattern instanceof BlockStateHolder) { + return setBlocks(region, (BlockStateHolder) pattern); + } + BlockReplace replace = new BlockReplace(this, pattern); + RegionVisitor visitor = new RegionVisitor(region, replace, queue instanceof MappedFaweQueue ? (MappedFaweQueue) queue : null); + Operations.completeBlindly(visitor); + return this.changes = 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.function.mask.ExistingBlockMask} + * @param replacement the replacement block + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + default > int replaceBlocks(Region region, Set filter, B replacement) throws MaxChangedBlocksException { + return replaceBlocks(region, filter, new BlockPattern(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.function.mask.ExistingBlockMask} + * @param pattern the pattern that provides the new blocks + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + default int replaceBlocks(Region region, Set filter, Pattern pattern) throws MaxChangedBlocksException { + Mask mask = filter == null ? new ExistingBlockMask(this) : new BlockMask(this, 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 + */ + default int replaceBlocks(Region region, Mask mask, Pattern pattern) throws MaxChangedBlocksException { + checkNotNull(region); + checkNotNull(mask); + checkNotNull(pattern); + + BlockReplace replace = new BlockReplace(this, pattern); + RegionMaskingFilter filter = new RegionMaskingFilter(mask, 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 + */ + default int center(Region region, Pattern pattern) throws MaxChangedBlocksException { + checkNotNull(region); + checkNotNull(pattern); + + Vector3 center = region.getCenter(); + Region centerRegion = new CuboidRegion( + getWorld(), // Causes clamping of Y range + BlockVector3.at(((int) center.getX()), ((int) center.getY()), ((int) center.getZ())), + BlockVector3.at(MathUtils.roundHalfUp(center.getX()), + center.getY(), MathUtils.roundHalfUp(center.getZ()))); + return setBlocks(centerRegion, pattern); + } + + default int setBlocks(final Set vset, final Pattern pattern) { + RegionVisitor visitor = new RegionVisitor(vset, new BlockReplace(getExtent(), pattern)); + Operations.completeBlindly(visitor); + return 0; + } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java index 53351e0b0..a7e73c1bd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java @@ -23,6 +23,8 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.MutableBlockVector2; +import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -50,7 +52,13 @@ public interface OutputExtent { * @return true if the block was successfully set (return value may not be accurate) * @throws WorldEditException thrown on an error */ - > boolean setBlock(BlockVector3 position, T block) throws WorldEditException; + default > boolean setBlock(BlockVector3 position, T block) throws WorldEditException { + return setBlock(position.getX(), position.getY(), position.getZ(), block); + } + + default > boolean setBlock(int x, int y, int z, T block) throws WorldEditException { + return setBlock(MutableBlockVector3.get(x, y, z), block); + } /** * Set the biome. @@ -59,7 +67,13 @@ public interface OutputExtent { * @param biome the biome to set to * @return true if the biome was successfully set (return value may not be accurate) */ - boolean setBiome(BlockVector2 position, BiomeType biome); + default boolean setBiome(BlockVector2 position, BiomeType biome) { + return setBiome(position.getX(), 0, position.getBlockZ(), biome); + } + + default boolean setBiome(int x, int y, int z, BiomeType biome) { + return setBiome(MutableBlockVector2.get(x, z), biome); + } /** * Return an {@link Operation} that should be called to tie up loose ends diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/PassthroughExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/PassthroughExtent.java new file mode 100644 index 000000000..c8df9204e --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/PassthroughExtent.java @@ -0,0 +1,177 @@ +package com.sk89q.worldedit.extent; + +import com.boydti.fawe.jnbt.anvil.generator.GenBase; +import com.boydti.fawe.jnbt.anvil.generator.Resource; +import com.boydti.fawe.object.extent.LightingExtent; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.OperationQueue; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.util.Countable; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; + +import javax.annotation.Nullable; +import java.util.List; + +public class PassthroughExtent extends AbstractDelegateExtent { + private final Extent extent; + + public PassthroughExtent(Extent parent) { + super(parent); + this.extent = parent; + } + + @Override + public List getEntities(Region region) { + return extent.getEntities(region); + } + + @Override + public List getEntities() { + return extent.getEntities(); + } + + @Override + @Nullable + public Entity createEntity(Location location, BaseEntity entity) { + return extent.createEntity(location, entity); + } + + @Override + public int getHighestTerrainBlock(int x, int z, int minY, int maxY) { + return extent.getHighestTerrainBlock(x, z, minY, maxY); + } + + @Override + public int getHighestTerrainBlock(int x, int z, int minY, int maxY, Mask filter) { + return extent.getHighestTerrainBlock(x, z, minY, maxY, filter); + } + + @Override + public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) { + return extent.getNearestSurfaceLayer(x, z, y, minY, maxY); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, boolean ignoreAir) { + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) { + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) { + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) { + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, boolean ignoreAir) { + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir); + } + + @Override + public void addCaves(Region region) throws WorldEditException { + extent.addCaves(region); + } + + @Override + public void generate(Region region, GenBase gen) throws WorldEditException { + extent.generate(region, gen); + } + + @Override + public void addSchems(Region region, Mask mask, List clipboards, int rarity, boolean rotate) throws WorldEditException { + extent.addSchems(region, mask, clipboards, rarity, rotate); + } + + @Override + public void spawnResource(Region region, Resource gen, int rarity, int frequency) throws WorldEditException { + extent.spawnResource(region, gen, rarity, frequency); + } + + @Override + public boolean contains(BlockVector3 pt) { + return extent.contains(pt); + } + + @Override + public void addOre(Region region, Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException { + extent.addOre(region, mask, material, size, frequency, rarity, minY, maxY); + } + + @Override + public void addOres(Region region, Mask mask) throws WorldEditException { + extent.addOres(region, mask); + } + + @Override + public List> getBlockDistribution(Region region) { + return extent.getBlockDistribution(region); + } + + @Override + public List> getBlockDistributionWithData(Region region) { + return extent.getBlockDistributionWithData(region); + } + + @Override + public BlockArrayClipboard lazyCopy(Region region) { + return extent.lazyCopy(region); + } + + @Override + public BlockState getBlock(BlockVector3 position) { + return extent.getBlock(position); + } + + @Override + public BlockType getBlockType(BlockVector3 position) { + return extent.getBlockType(position); + } + + @Override + public BaseBlock getFullBlock(BlockVector3 position) { + return extent.getFullBlock(position); + } + + @Override + public BiomeType getBiome(BlockVector2 position) { + return extent.getBiome(position); + } + + @Override + public > boolean setBlock(BlockVector3 position, T block) throws WorldEditException { + return extent.setBlock(position, block); + } + + @Override + public > boolean setBlock(int x, int y, int z, T block) throws WorldEditException { + return extent.setBlock(x, y, z, block); + } + + @Override + public boolean setBiome(BlockVector2 position, BiomeType biome) { + return extent.setBiome(position, biome); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java index 6ac7a20a7..e56605c2e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java @@ -117,7 +117,7 @@ public class BlockArrayClipboard implements Clipboard, LightingExtent, Closeable } @Override - protected void finalize() throws Throwable { + protected void finalize() { close(); } @@ -196,11 +196,6 @@ public class BlockArrayClipboard implements Clipboard, LightingExtent, Closeable return BlockTypes.AIR.getDefaultState(); } - @Override - public BlockState getLazyBlock(BlockVector3 position) { - return getBlock(position); - } - @Override public BaseBlock getFullBlock(BlockVector3 position) { if(region.contains(position)) { @@ -266,8 +261,6 @@ public class BlockArrayClipboard implements Clipboard, LightingExtent, Closeable return null; } - - @Override public int getLight(int x, int y, int z) { return getBlockLight(x, y, z); @@ -285,11 +278,11 @@ public class BlockArrayClipboard implements Clipboard, LightingExtent, Closeable @Override public int getOpacity(int x, int y, int z) { - return getBlock(BlockVector3.at(x, y, z)).getBlockType().getMaterial().getLightOpacity(); + return getBlock(x, y, z).getBlockType().getMaterial().getLightOpacity(); } @Override public int getBrightness(int x, int y, int z) { - return getBlock(BlockVector3.at(x, y, z)).getBlockType().getMaterial().getLightValue(); + return getBlock(x, y, z).getBlockType().getMaterial().getLightValue(); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java index aeaf07e85..6994442fe 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java @@ -61,7 +61,7 @@ public interface Clipboard extends Extent { /** * Returns true if the clipboard has biome data. This can be checked since {@link Extent#getBiome(BlockVector2)} - * strongly suggests returning {@link com.sk89q.worldedit.world.biome.BiomeTypes.OCEAN} instead of {@code null} + * strongly suggests returning {@link com.sk89q.worldedit.world.biome.BiomeTypes#OCEAN} instead of {@code null} * if biomes aren't present. However, it might not be desired to set areas to ocean if the clipboard is defaulting * to ocean, instead of having biomes explicitly set. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java index 3d646866d..1813d2240 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java @@ -22,7 +22,8 @@ package com.sk89q.worldedit.extent.clipboard.io; import com.boydti.fawe.object.io.PGZIPOutputStream; import com.boydti.fawe.object.io.ResettableFileInputStream; import com.boydti.fawe.object.schematic.PNGWriter; -import com.boydti.fawe.object.schematic.StructureFormat; +import com.boydti.fawe.object.schematic.MinecraftStructure; + import com.google.common.collect.ImmutableSet; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.NBTInputStream; @@ -122,35 +123,41 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { * The structure block format: * http://minecraft.gamepedia.com/Structure_block_file_format */ - STRUCTURE("structure", "nbt") { + MINECRAFT_STRUCTURE("structure") { + @Override + public String getPrimaryFileExtension() { + return "nbt"; + } + @Override public ClipboardReader getReader(InputStream inputStream) throws IOException { inputStream = new BufferedInputStream(inputStream); NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(inputStream))); - return new StructureFormat(nbtStream); + return new MinecraftStructure(nbtStream); } @Override public ClipboardWriter getWriter(OutputStream outputStream) throws IOException { outputStream = new BufferedOutputStream(outputStream); - OutputStream gzip; - if (outputStream instanceof PGZIPOutputStream || outputStream instanceof GZIPOutputStream) { - gzip = outputStream; - } else { - gzip = new PGZIPOutputStream(outputStream); - } + OutputStream gzip = new PGZIPOutputStream(outputStream); NBTOutputStream nbtStream = new NBTOutputStream(new BufferedOutputStream(gzip)); - return new StructureFormat(nbtStream); + return new MinecraftStructure(nbtStream); } @Override public boolean isFormat(File file) { - return file.getName().toLowerCase().endsWith(".nbt"); - } + try (NBTInputStream str = new NBTInputStream(new GZIPInputStream(new FileInputStream(file)))) { + NamedTag rootTag = str.readNamedTag(); + CompoundTag structureTag = (CompoundTag) rootTag.getTag(); + Map structure = structureTag.getValue(); + if (!structure.containsKey("DataVersion")) { + return false; + } + } catch (Exception e) { + return false; + } - @Override - public String getPrimaryFileExtension() { - return "nbt"; + return true; } }, diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java index 581724f2b..2d0c56d43 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java @@ -70,7 +70,7 @@ public class ClipboardFormats { checkNotNull(format); for (String key : format.getAliases()) { - String lowKey = key.toLowerCase(Locale.ENGLISH); + String lowKey = key.toLowerCase(Locale.ROOT); ClipboardFormat old = aliasMap.put(lowKey, format); if (old != null) { aliasMap.put(lowKey, old); @@ -78,7 +78,7 @@ public class ClipboardFormats { } } for (String ext : format.getFileExtensions()) { - String lowExt = ext.toLowerCase(Locale.ENGLISH); + String lowExt = ext.toLowerCase(Locale.ROOT); fileExtensionMap.put(lowExt, format); } registeredFormats.add(format); @@ -100,7 +100,7 @@ public class ClipboardFormats { @Nullable public static ClipboardFormat findByAlias(String alias) { checkNotNull(alias); - return aliasMap.get(alias.toLowerCase(Locale.ENGLISH).trim()); + return aliasMap.get(alias.toLowerCase(Locale.ROOT).trim()); } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagExtent.java index c6e508058..a65134097 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagExtent.java @@ -44,7 +44,7 @@ public class BlockBagExtent extends AbstractDelegateExtent { private final boolean mine; private int[] missingBlocks = new int[BlockTypes.size()]; - private BlockBag blockBag; + private final BlockBag blockBag; /** * Create a new instance. @@ -72,15 +72,6 @@ public class BlockBagExtent extends AbstractDelegateExtent { 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. @@ -106,31 +97,27 @@ public class BlockBagExtent extends AbstractDelegateExtent { @Override public > boolean setBlock(int x, int y, int z, B block) throws WorldEditException { - if (blockBag != null) { - BlockState existing = getLazyBlock(x, y, z); - - if (!block.getBlockType().equals(existing.getBlockType())) { - if (!block.getBlockType().getMaterial().isAir()) { - try { - blockBag.fetchPlacedBlock(block.toImmutableState()); - } catch (UnplaceableBlockException e) { - throw new FaweException.FaweBlockBagException(); - } catch (BlockBagException e) { - missingBlocks[block.getBlockType().getInternalId()]++; - throw new FaweException.FaweBlockBagException(); - } + BlockState existing = getBlock(x, y, z); + if (!block.getBlockType().equals(existing.getBlockType())) { + if (!block.getBlockType().getMaterial().isAir()) { + try { + blockBag.fetchPlacedBlock(block.toImmutableState()); + } catch (UnplaceableBlockException e) { + throw FaweException.BLOCK_BAG; + } catch (BlockBagException e) { + missingBlocks[block.getBlockType().getInternalId()]++; + throw FaweException.BLOCK_BAG; } - if (mine) { - if (!existing.getBlockType().getMaterial().isAir()) { - try { - blockBag.storeDroppedBlock(existing); - } catch (BlockBagException ignored) { - } + } + if (mine) { + if (!existing.getBlockType().getMaterial().isAir()) { + try { + blockBag.storeDroppedBlock(existing); + } catch (BlockBagException ignored) { } } } } - return super.setBlock(x, y, z, block); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/RegionFunction.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/RegionFunction.java index 332565e35..25f5f22d7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/RegionFunction.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/RegionFunction.java @@ -35,5 +35,4 @@ public interface RegionFunction { * @throws WorldEditException thrown on an error */ boolean apply(BlockVector3 position) throws WorldEditException; - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ABlockMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ABlockMask.java new file mode 100644 index 000000000..5f26ef942 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ABlockMask.java @@ -0,0 +1,84 @@ +package com.sk89q.worldedit.function.mask; + +import com.boydti.fawe.util.StringMan; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.util.command.parametric.Optional; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +public abstract class ABlockMask extends AbstractExtentMask { + public ABlockMask(Extent extent) { + super(extent); + } + + public abstract boolean test(BlockState state); + + @Override + public String toString() { + List strings = new ArrayList<>(); + for (BlockType type : BlockTypes.values) { + if (type != null) { + boolean hasAll = true; + boolean hasAny = false; + List all = type.getAllStates(); + for (BlockState state : all) { + hasAll &= test(state); + hasAny = true; + } + if (hasAll) { + strings.add(type.getId()); + } else if (hasAny) { + for (BlockState state : all) { + if (test(state)) { + strings.add(state.getAsString()); + } + } + } + } + } + return StringMan.join(strings, ","); + } + + @Override + public Mask and(Mask mask) { + if (mask instanceof ABlockMask) { + ABlockMask other = (ABlockMask) mask; + BlockMask newMask = new BlockMask(getExtent()); + for (BlockState state : BlockTypes.states) { + if (state != null) { + if (test(state) && other.test(state)) { + newMask.add(state); + } + } + } + Mask tmp = newMask.optimize(); + if (tmp == null) tmp = newMask; + return tmp; + } + return null; + } + + @Override + public Mask or(Mask mask) { + if (mask instanceof ABlockMask) { + ABlockMask other = (ABlockMask) mask; + BlockMask newMask = new BlockMask(getExtent()); + for (BlockState state : BlockTypes.states) { + if (state != null) { + if (test(state) || other.test(state)) { + newMask.add(state); + } + } + } + Mask tmp = newMask.optimize(); + if (tmp == null) tmp = newMask; + return tmp; + } + return null; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/AbstractExtentMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/AbstractExtentMask.java index dbb3f28cc..a5478156c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/AbstractExtentMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/AbstractExtentMask.java @@ -44,7 +44,7 @@ public abstract class AbstractExtentMask extends AbstractMask { * * @return the extent */ - public Extent getExtent() { + public final Extent getExtent() { return extent; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java index 625d8b781..6719f7587 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java @@ -20,13 +20,10 @@ package com.sk89q.worldedit.function.mask; import static com.google.common.base.Preconditions.checkNotNull; - import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BlockCategory; -import javax.annotation.Nullable; - /** * A mask that tests whether a block matches a given {@link BlockCategory}, or tag. */ @@ -42,12 +39,7 @@ public class BlockCategoryMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { - return category.contains(getExtent().getBlock(vector)); + return category.contains(vector.getBlock(getExtent())); } - @Nullable - @Override - public Mask2D toMask2D() { - return null; - } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockStateMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockStateMask.java index 69e47039d..7e5acdc94 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockStateMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockStateMask.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.function.mask; +import com.boydti.fawe.beta.FilterBlock; import com.google.common.collect.Maps; import com.sk89q.worldedit.blocks.Blocks; import com.sk89q.worldedit.extent.Extent; @@ -27,9 +28,9 @@ import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; -import javax.annotation.Nullable; import java.util.Map; +@Deprecated public class BlockStateMask extends AbstractExtentMask { private final Map states; @@ -52,7 +53,10 @@ public class BlockStateMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { - BlockState block = getExtent().getBlock(vector); + return test(vector.getBlock(getExtent())); + } + + public boolean test(BlockState block) { final Map, Object> checkProps = cache .computeIfAbsent(block.getBlockType(), (b -> Blocks.resolveProperties(states, b))); if (strict && checkProps.isEmpty()) { @@ -62,9 +66,4 @@ public class BlockStateMask extends AbstractExtentMask { .allMatch(entry -> block.getState(entry.getKey()) == entry.getValue()); } - @Nullable - @Override - public Mask2D toMask2D() { - return null; - } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java index 2f72d5a1d..e31567191 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java @@ -20,11 +20,8 @@ package com.sk89q.worldedit.function.mask; import static com.google.common.base.Preconditions.checkArgument; - import com.sk89q.worldedit.math.BlockVector3; -import javax.annotation.Nullable; - /** * Has the criteria where the Y value of passed positions must be within * a certain range of Y values (inclusive). @@ -51,10 +48,4 @@ public class BoundedHeightMask extends AbstractMask { return vector.getY() >= minY && vector.getY() <= maxY; } - @Nullable - @Override - public Mask2D toMask2D() { - return null; - } - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java index ac4d24452..e8bef2c08 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java @@ -19,11 +19,10 @@ package com.sk89q.worldedit.function.mask; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; -import javax.annotation.Nullable; - /** * A mask that returns true whenever the block at the location is not * an air block (it contains some other block). @@ -41,13 +40,7 @@ public class ExistingBlockMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { - return !getExtent().getBlock(vector).getBlockType().getMaterial().isAir(); - } - - @Nullable - @Override - public Mask2D toMask2D() { - return null; + return !vector.getBlock(getExtent()).getMaterial().isAir(); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseMask.java index 3999dfc44..4a22ef5fd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseMask.java @@ -2,6 +2,7 @@ package com.sk89q.worldedit.function.mask; import javax.annotation.Nullable; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.math.BlockVector3; public class InverseMask extends AbstractMask { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockStateMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockStateMask.java new file mode 100644 index 000000000..024a61812 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockStateMask.java @@ -0,0 +1,38 @@ +package com.sk89q.worldedit.function.mask; + +import com.boydti.fawe.beta.FilterBlock; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.Arrays; + +public class InverseSingleBlockStateMask extends ABlockMask { + private final char ordinal; + + public BlockStateHolder getBlockState() { + return BlockState.getFromOrdinal(ordinal); + } + + public InverseSingleBlockStateMask(Extent extent, BlockState state) { + super(extent); + this.ordinal = state.getOrdinalChar(); + } + + @Override + public boolean test(BlockVector3 vector) { + return ordinal != vector.getOrdinal(getExtent()); + } + + @Override + public final boolean test(BlockState state) { + return state.getOrdinalChar() != ordinal; + } + + @Override + public Mask inverse() { + return new SingleBlockStateMask(getExtent(), BlockState.getFromOrdinal(ordinal)); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockTypeMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockTypeMask.java new file mode 100644 index 000000000..8c800a743 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockTypeMask.java @@ -0,0 +1,37 @@ +package com.sk89q.worldedit.function.mask; + +import com.boydti.fawe.beta.FilterBlock; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; + +public class InverseSingleBlockTypeMask extends ABlockMask { + private final int internalId; + + public InverseSingleBlockTypeMask(Extent extent, BlockType type) { + super(extent); + this.internalId = type.getInternalId(); + } + + @Override + public boolean test(BlockVector3 vector) { + return test(vector.getBlock(getExtent())); + } + + @Override + public final boolean test(BlockState state) { + return state.getBlockType().getInternalId() != internalId; + } + + @Override + public Mask inverse() { + return new SingleBlockTypeMask(getExtent(), BlockTypes.values[internalId]); + } + + public BlockType getBlockType() { + return BlockTypes.get(internalId); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java index 1283b0bb2..359a38175 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java @@ -19,8 +19,12 @@ package com.sk89q.worldedit.function.mask; +import com.boydti.fawe.beta.DelegateFilter; +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.minecraft.util.commands.Link; import com.sk89q.worldedit.command.UtilityCommands; +import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import javax.annotation.Nullable; @@ -39,6 +43,28 @@ public interface Mask { */ boolean test(BlockVector3 vector); + default Filter toFilter(Runnable run) { + return new Filter() { + @Override + public void applyBlock(FilterBlock block) { + if (test(block)) { + run.run(); + } + } + }; + } + + default DelegateFilter toFilter(T filter) { + return new DelegateFilter(filter) { + @Override + public void applyBlock(FilterBlock block) { + if (test(block)) { + filter.applyBlock(block); + } + } + }; + } + /** * Get the 2D version of this mask if one exists. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection.java index 051f904f8..dba2b6743 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection.java @@ -178,10 +178,6 @@ public class MaskIntersection extends AbstractMask { @Override public boolean test(BlockVector3 vector) { - if (masks.isEmpty()) { - return false; - } - for (Mask mask : masksArray) { if (!mask.test(vector)) { return false; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java index 00ce54dec..7c8bb0a61 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.function.mask; +import com.boydti.fawe.beta.FilterBlock; import com.google.common.base.Function; import com.sk89q.worldedit.math.BlockVector3; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Masks.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Masks.java index 3023c62ce..dd85587c7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Masks.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Masks.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.function.mask; import static com.google.common.base.Preconditions.checkNotNull; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; @@ -140,7 +141,7 @@ public final class Masks { @Override public Mask or(Mask other) { - return other; + return this; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java index c870d4786..854d9471d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java @@ -22,7 +22,9 @@ package com.sk89q.worldedit.function.mask; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.MutableVector3; import com.sk89q.worldedit.math.noise.NoiseGenerator; import javax.annotation.Nullable; @@ -85,8 +87,8 @@ public class NoiseFilter extends AbstractMask { } @Override - public boolean test(BlockVector3 vector) { - return noiseGenerator.noise(vector.toVector3()) <= density; + public boolean test(BlockVector3 v) { + return noiseGenerator.noise(MutableVector3.get(v.getX(), v.getY(), v.getZ())) <= density; } @Nullable diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java index e5df3b153..a5d40b12f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.function.mask; import static com.google.common.base.Preconditions.checkNotNull; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.math.BlockVector3; import javax.annotation.Nullable; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/RegionMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/RegionMask.java index 28df2c206..c3305d597 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/RegionMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/RegionMask.java @@ -20,12 +20,9 @@ package com.sk89q.worldedit.function.mask; import static com.google.common.base.Preconditions.checkNotNull; - import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; -import javax.annotation.Nullable; - /** * A mask that tests whether given positions are contained within a region. */ @@ -66,10 +63,4 @@ public class RegionMask extends AbstractMask { return region.contains(vector); } - @Nullable - @Override - public Mask2D toMask2D() { - return null; - } - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SingleBlockStateBitMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SingleBlockStateBitMask.java deleted file mode 100644 index 24da28c8f..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SingleBlockStateBitMask.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.sk89q.worldedit.function.mask; - -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.math.BlockVector3; - -public class SingleBlockStateBitMask extends AbstractExtentMask { - private final int bitMask; - - protected SingleBlockStateBitMask(Extent extent, int bitMask) { - super(extent); - this.bitMask = bitMask; - } - - @Override - public boolean test(BlockVector3 vector) { - int internalId = getExtent().getBlock(vector).getInternalId(); - return (internalId & bitMask) == internalId; - } -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SingleBlockStateMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SingleBlockStateMask.java index ea5fd15b3..3507571e8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SingleBlockStateMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SingleBlockStateMask.java @@ -1,28 +1,50 @@ package com.sk89q.worldedit.function.mask; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypes; -public class SingleBlockStateMask extends AbstractExtentMask { - private final BlockStateHolder state; +import java.util.Arrays; + +public class SingleBlockStateMask extends ABlockMask { + private final char ordinal; public BlockStateHolder getBlockState() { - return state; + return BlockState.getFromOrdinal(ordinal); } - public SingleBlockStateMask(Extent extent, BlockStateHolder state) { + public SingleBlockStateMask(Extent extent, BlockState state) { super(extent); - this.state = state; + this.ordinal = state.getOrdinalChar(); } @Override public boolean test(BlockVector3 vector) { - return state.equals(getExtent().getBlock(vector)); + return ordinal == vector.getOrdinal(getExtent()); + } + + @Override + public final boolean test(BlockState state) { + return state.getOrdinalChar() == ordinal; } @Override public Mask inverse() { - return new BlockMaskBuilder().add(state).build(getExtent()).inverse(); + return new InverseSingleBlockStateMask(getExtent(), BlockState.getFromOrdinal(ordinal)); + } + + @Override + public Mask and(Mask mask) { + if (mask instanceof ABlockMask) { + ABlockMask other = (ABlockMask) mask; + if (other.test(BlockState.getFromOrdinal(ordinal))) { + return this; + } + return Masks.alwaysFalse(); + } + return null; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/BlockPattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/BlockPattern.java index 6fb46180f..6ad68f5f9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/BlockPattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/BlockPattern.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.function.pattern; import static com.google.common.base.Preconditions.checkNotNull; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -66,5 +67,4 @@ public class BlockPattern extends AbstractPattern { public BaseBlock apply(BlockVector3 position) { return block; } - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/FawePattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/FawePattern.java index 8edd7942c..f062bb075 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/FawePattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/FawePattern.java @@ -14,17 +14,17 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; */ @Link(clazz = UtilityCommands.class, value = "patterns") public interface FawePattern extends Pattern { - - @Deprecated - default BaseBlock apply(BlockVector3 position) { - throw new UnsupportedOperationException("Please use apply(extent, get, set)"); - } - - /** - * Return a {@link BlockStateHolder} for the given position. - * - * @return a block - */ - @Override - boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException; +// +// @Deprecated +// default BaseBlock apply(BlockVector3 position) { +// throw new UnsupportedOperationException("Please use apply(extent, get, set)"); +// } +// +// /** +// * Return a {@link BlockStateHolder} for the given position. +// * +// * @return a block +// */ +// @Override +// boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java index 2c000c668..9791bb8ce 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java @@ -19,6 +19,8 @@ package com.sk89q.worldedit.function.pattern; +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.minecraft.util.commands.Link; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.UtilityCommands; @@ -31,7 +33,7 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; * Returns a {@link BlockStateHolder} for a given position. */ @Link(clazz = UtilityCommands.class, value = "patterns") -public interface Pattern { +public interface Pattern extends Filter { /** * Return a {@link BlockStateHolder} for the given position. @@ -42,6 +44,11 @@ public interface Pattern { BaseBlock apply(BlockVector3 position); default boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - return extent.setBlock(set, apply(get)); + return set.setFullBlock(extent, apply(get)); + } + + @Override + default void applyBlock(final FilterBlock block) { + apply(block, block, block); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java index 601567ef9..b9f2bc2ba 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.function.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.object.collection.RandomCollection; import com.boydti.fawe.object.random.SimpleRandom; import com.boydti.fawe.object.random.TrueRandom; @@ -84,8 +85,8 @@ public class RandomPattern extends AbstractPattern { } @Override - public boolean apply(Extent extent, BlockVector3 set, BlockVector3 get) throws WorldEditException { - return collection.next(get.getBlockX(), get.getBlockY(), get.getBlockZ()).apply(extent, set, get); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + return collection.next(get.getBlockX(), get.getBlockY(), get.getBlockZ()).apply(extent, get, set); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java index 12add6726..0746ac06b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.function.pattern; import static com.google.common.base.Preconditions.checkNotNull; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.MutableBlockVector3; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DirectionalVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DirectionalVisitor.java index 8a9542e32..27aa99562 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DirectionalVisitor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DirectionalVisitor.java @@ -19,15 +19,10 @@ package com.sk89q.worldedit.function.visitor; -import com.boydti.fawe.object.HasFaweQueue; -import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.math.BlockVector3; -import java.util.Collection; - - import static com.google.common.base.Preconditions.checkNotNull; /** @@ -43,22 +38,23 @@ public class DirectionalVisitor extends RecursiveVisitor { private final BlockVector3 dirVec; public DirectionalVisitor(Mask mask, RegionFunction function, BlockVector3 origin, BlockVector3 direction) { - this(mask, function, origin, direction, Integer.MAX_VALUE, null); + this(mask, function, origin, direction, Integer.MAX_VALUE); } - public DirectionalVisitor(Mask mask, RegionFunction function, BlockVector3 origin, BlockVector3 direction, int distance, HasFaweQueue hasFaweQueue) { - super(mask, function, distance, hasFaweQueue); + public DirectionalVisitor(Mask mask, RegionFunction function, BlockVector3 origin, BlockVector3 direction, int distance) { + super(mask, function, distance); checkNotNull(mask); this.origin = origin; this.dirVec = direction; - final Collection directions = this.getDirections(); - directions.clear(); - directions.add(BlockVector3.at(1, 0, 0)); - directions.add(BlockVector3.at(-1, 0, 0)); - directions.add(BlockVector3.at(0, 0, 1)); - directions.add(BlockVector3.at(0, 0, -1)); - directions.add(BlockVector3.at(0, -1, 0)); - directions.add(BlockVector3.at(0, 1, 0)); + + setDirections( + BlockVector3.at(1, 0, 0), + BlockVector3.at(-1, 0, 0), + BlockVector3.at(0, 0, 1), + BlockVector3.at(0, 0, -1), + BlockVector3.at(0, -1, 0), + BlockVector3.at(0, 1, 0) + ); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java index e20007841..33a1dde10 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java @@ -57,13 +57,13 @@ public class DownwardVisitor extends RecursiveVisitor { this.baseY = baseY; - Collection directions = getDirections(); - directions.clear(); - directions.add(BlockVector3.UNIT_X); - directions.add(BlockVector3.UNIT_MINUS_X); - directions.add(BlockVector3.UNIT_Z); - directions.add(BlockVector3.UNIT_MINUS_Z); - directions.add(BlockVector3.UNIT_MINUS_Y); + setDirections( + BlockVector3.UNIT_X, + BlockVector3.UNIT_MINUS_X, + BlockVector3.UNIT_Z, + BlockVector3.UNIT_MINUS_Z, + BlockVector3.UNIT_MINUS_Y + ); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java index cc74ffce7..e932d8c2d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java @@ -44,13 +44,13 @@ public class NonRisingVisitor extends RecursiveVisitor { public NonRisingVisitor(Mask mask, RegionFunction function, int depth, HasFaweQueue hasFaweQueue) { super(mask, function, depth, hasFaweQueue); - Collection directions = getDirections(); - directions.clear(); - directions.add(BlockVector3.UNIT_X); - directions.add(BlockVector3.UNIT_MINUS_X); - directions.add(BlockVector3.UNIT_Z); - directions.add(BlockVector3.UNIT_MINUS_Z); - directions.add(BlockVector3.UNIT_MINUS_Y); + setDirections( + BlockVector3.UNIT_X, + BlockVector3.UNIT_MINUS_X, + BlockVector3.UNIT_Z, + BlockVector3.UNIT_MINUS_Z, + BlockVector3.UNIT_MINUS_Y + ); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/RecursiveVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/RecursiveVisitor.java index 6564ff54f..0ce97d0c8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/RecursiveVisitor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/RecursiveVisitor.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.function.visitor; -import com.boydti.fawe.object.HasFaweQueue; import static com.google.common.base.Preconditions.checkNotNull; import com.sk89q.worldedit.function.RegionFunction; @@ -45,11 +44,7 @@ public class RecursiveVisitor extends BreadthFirstSearch { * @param function the function */ public RecursiveVisitor(Mask mask, RegionFunction function, int maxDepth) { - this(mask, function, maxDepth, null); - } - - public RecursiveVisitor(Mask mask, RegionFunction function, int maxDepth, HasFaweQueue faweQueue) { - super(function, maxDepth, faweQueue); + super(function, maxDepth); checkNotNull(mask); this.mask = mask; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java index 01bdae460..0fac8e499 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java @@ -20,13 +20,6 @@ package com.sk89q.worldedit.function.visitor; import com.boydti.fawe.config.BBC; -import com.boydti.fawe.config.Settings; -import com.boydti.fawe.example.MappedFaweQueue; -import com.boydti.fawe.object.FaweQueue; -import com.boydti.fawe.object.HasFaweQueue; -import com.boydti.fawe.object.exception.FaweException; - -import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.operation.Operation; @@ -34,7 +27,6 @@ import com.sk89q.worldedit.function.operation.RunContext; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; -import java.util.Iterator; import java.util.List; /** @@ -48,7 +40,6 @@ public class RegionVisitor implements Operation { public final RegionFunction function; public int affected = 0; public final Iterable iterable; - private final MappedFaweQueue queue; /** * Deprecated in favor of the other constructors which will preload chunks during iteration @@ -57,22 +48,14 @@ public class RegionVisitor implements Operation { * @param function */ public RegionVisitor(Region region, RegionFunction function) { - this(region, function, (FaweQueue) null); + this((Iterable) region, function); } - public RegionVisitor(Region region, RegionFunction function, EditSession editSession) { - this(region, function, editSession != null ? editSession.getQueue() : null); - } - - public RegionVisitor(Region region, RegionFunction function, FaweQueue queue) { - this((Iterable) region, function, queue); - } - - public RegionVisitor(Iterable iterable, RegionFunction function, HasFaweQueue hasQueue) { + @Deprecated + public RegionVisitor(Iterable iterable, RegionFunction function) { this.region = iterable instanceof Region ? (Region) iterable : null; this.function = function; this.iterable = iterable; - this.queue = hasQueue != null && hasQueue.getQueue() instanceof MappedFaweQueue ? (MappedFaweQueue) hasQueue.getQueue() : null; } /** @@ -86,100 +69,8 @@ public class RegionVisitor implements Operation { @Override public Operation resume(RunContext run) throws WorldEditException { - if (queue != null && Settings.IMP.QUEUE.PRELOAD_CHUNKS > 1) { - /* - * The following is done to reduce iteration cost - * - Preload chunks just in time - * - Only check every 16th block for potential chunk loads - * - Stop iteration on exception instead of hasNext - * - Do not calculate the stacktrace as it is expensive - */ - Iterator trailIter = iterable.iterator(); - Iterator leadIter = iterable.iterator(); - int lastTrailChunkX = Integer.MIN_VALUE; - int lastTrailChunkZ = Integer.MIN_VALUE; - int lastLeadChunkX = Integer.MIN_VALUE; - int lastLeadChunkZ = Integer.MIN_VALUE; - int loadingTarget = Settings.IMP.QUEUE.PRELOAD_CHUNKS; - try { - for (; ; ) { - BlockVector3 pt = trailIter.next(); - apply(pt); - int cx = pt.getBlockX() >> 4; - int cz = pt.getBlockZ() >> 4; - if (cx != lastTrailChunkX || cz != lastTrailChunkZ) { - lastTrailChunkX = cx; - lastTrailChunkZ = cz; - int amount; - if (lastLeadChunkX == Integer.MIN_VALUE) { - lastLeadChunkX = cx; - lastLeadChunkZ = cz; - amount = loadingTarget; - } else { - amount = 1; - } - for (int count = 0; count < amount; ) { - BlockVector3 v = leadIter.next(); - int vcx = v.getBlockX() >> 4; - int vcz = v.getBlockZ() >> 4; - if (vcx != lastLeadChunkX || vcz != lastLeadChunkZ) { - lastLeadChunkX = vcx; - lastLeadChunkZ = vcz; - queue.queueChunkLoad(vcx, vcz); - count++; - } - // Skip the next 15 blocks - leadIter.next(); - leadIter.next(); - leadIter.next(); - leadIter.next(); - leadIter.next(); - leadIter.next(); - leadIter.next(); - leadIter.next(); - leadIter.next(); - leadIter.next(); - leadIter.next(); - leadIter.next(); - leadIter.next(); - leadIter.next(); - leadIter.next(); - } - } - apply(trailIter.next()); - apply(trailIter.next()); - apply(trailIter.next()); - apply(trailIter.next()); - apply(trailIter.next()); - apply(trailIter.next()); - apply(trailIter.next()); - apply(trailIter.next()); - apply(trailIter.next()); - apply(trailIter.next()); - apply(trailIter.next()); - apply(trailIter.next()); - apply(trailIter.next()); - apply(trailIter.next()); - apply(trailIter.next()); - } - } catch (FaweException e) { - throw new RuntimeException(e); - } catch (Throwable ignore) { - ignore.printStackTrace(); - } - try { - while (true) { - apply(trailIter.next()); - apply(trailIter.next()); - } - } catch (FaweException e) { - throw new RuntimeException(e); - } catch (Throwable ignore) { - } - } else { - for (BlockVector3 pt : iterable) { - apply(pt); - } + for (BlockVector3 pt : iterable) { + apply(pt); } return null; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/ScanChunk.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/ScanChunk.java new file mode 100644 index 000000000..96ce3ca37 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/ScanChunk.java @@ -0,0 +1,342 @@ +package com.sk89q.worldedit.function.visitor; + +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.util.MathMan; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.math.BlockVector3; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.longs.LongArraySet; +import it.unimi.dsi.fastutil.objects.ObjectIterator; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.ConcurrentLinkedQueue; + +/** + * A chunk based search algorithm + */ +public class ScanChunk { + private static final int MAX_QUEUE = 34816; + public static final BlockVector3[] DEFAULT_DIRECTIONS = new BlockVector3[6]; + public static final BlockVector3[] DIAGONAL_DIRECTIONS; + + static { + DEFAULT_DIRECTIONS[0] = (BlockVector3.at(0, -1, 0)); + DEFAULT_DIRECTIONS[1] = (BlockVector3.at(0, 1, 0)); + DEFAULT_DIRECTIONS[2] = (BlockVector3.at(-1, 0, 0)); + DEFAULT_DIRECTIONS[3] = (BlockVector3.at(1, 0, 0)); + DEFAULT_DIRECTIONS[4] = (BlockVector3.at(0, 0, -1)); + DEFAULT_DIRECTIONS[5] = (BlockVector3.at(0, 0, 1)); + List list = new ArrayList<>(); + for (int x = -1; x <= 1; x++) { + for (int y = -1; y <= 1; y++) { + for (int z = -1; z <= 1; z++) { + if (x != 0 || y != 0 || z != 0) { + BlockVector3 pos = BlockVector3.at(x, y, z); + if (!list.contains(pos)) { + list.add(pos); + } + } + } + } + } + Collections.sort(list, new Comparator() { + @Override + public int compare(BlockVector3 o1, BlockVector3 o2) { + return (int) Math.signum(o1.lengthSq() - o2.lengthSq()); + } + }); + DIAGONAL_DIRECTIONS = list.toArray(new BlockVector3[list.size()]); + } + + private final RegionFunction function; + private final BlockVector3[] directions; + private final Long2ObjectOpenHashMap visits; + private final Long2ObjectOpenHashMap queues; + + public ScanChunk(final RegionFunction function) { + this.function = function; + this.directions = DEFAULT_DIRECTIONS; + + this.queues = new Long2ObjectOpenHashMap<>(); + this.visits = new Long2ObjectOpenHashMap<>(); + } + + public static final long pairInt(int x, int y) { + return (((long) x) << 32) | (y & 0xffffffffL); + } + + public boolean isVisited(int x, int y, int z) { + int X = x >> 4; + int Z = z >> 4; + long pair = pairInt(X, Z); + long[][] chunk = visits.get(pair); + if (chunk == null) return false; + int layer = y >> 4; + long[] section = chunk[layer]; + if (section == null) return false; + return get(section, getLocalIndex(x & 15, y & 15, z & 15)); + } + + public void start(int x, int y, int z) { + if (!isVisited(x, y, z)) { + push(x, y, z); + visit(x, y, z); + } + } + + public void visit(int x, int y, int z) { + int X = x >> 4; + int Z = z >> 4; + long pair = pairInt(X, Z); + long[][] arrs = visits.get(pair); + if (arrs == null) { + visits.put(pair, arrs = new long[16][]); + } + int layer = y >> 4; + long[] section = arrs[layer]; + if (section == null) { + arrs[layer] = section = new long[64]; + } + set(section, getLocalIndex(x & 15, y & 15, z & 15)); + } + + private char[] getOrCreateQueue(long pair, int layer) { + char[][] arrs = queues.get(pair); + if (arrs == null) { + queues.put(pair, arrs = new char[16][]); + } + + char[] section = arrs[layer]; + if (section == null) { + arrs[layer] = section = newQueue(); + } + return section; + } + + private void push(int x, int y, int z) { + int X = x >> 4; + int Z = z >> 4; + long pair = pairInt(X, Z); + int layer = y >> 4; + char[] section = getOrCreateQueue(pair, layer); + push(section, x & 15, y & 15, z & 15); + } + + private void push(char[] queue, int x, int y, int z) { + char indexStart = queue[0]; + char indexEnd = queue[1]; + push(indexStart, indexEnd, queue, x, y, z); + } + + private void push(char indexStart, char indexEnd, char[] queue, int x, int y, int z) { + char index = getLocalIndex(x, y, z); + if (indexStart > 2) { + queue[0] = --indexStart; + queue[indexStart] = index; + } else { + queue[indexEnd] = index; + queue[0] = ++indexEnd; + } + } + + public void process() { + LongArraySet set = new LongArraySet(); + while (!queues.isEmpty()) { +// ObjectIterator> iter = queues.long2ObjectEntrySet().fastIterator(); +// Long2ObjectMap.Entry entry = iter.next(); +// long index = entry.getLongKey(); +// int X = MathMan.unpairIntX(index); +// int Z = MathMan.unpairIntY(index); +// // check that adjacent chunks aren;t being processed +// +// char[] queue = entry.getValue(); +// long[][] visit = visits.get(index); +// if (visit == null) { +// visits.put(index, visit = new long[16][]); +// } + } + } + + private ConcurrentLinkedQueue queuePool = new ConcurrentLinkedQueue<>(); + + private char[] newQueue() { + char[] arr = queuePool.poll(); + if (arr != null) { + arr[0] = 2; + arr[1] = 2; + return arr; + } + return new char[4096]; + } + + public void process4(int xx, int yy, int zz, char[] queue, long[] visit) { + char index; + while ((index = queue[0]) != queue[1]) { + queue[0]++; + + char triple = queue[index]; + int x = index & 15; + int z = (index >> 4) & 15; + int y = index >> 8; + + int absX = xx + x; + int absY = yy + y; + int absZ = zz + z; + + apply(xx + x, yy + y, zz + z); + + int x1 = x, x2 = x; + + // find start of scan-line + int i1 = index; + while (true) { + if (x1 < 0) { + // queue in west chunk + break; + } + if (get(visit, i1)) break; + // visit + set(visit, i1); + + i1--; + x1--; + } + i1++; + x1++; + + // find end of scan-line + int i2 = index; + while (true) { + if (x2 > 15) { + // queue in east chunk + break; + } + if (get(visit, i2)) break; + set(visit, i2); + i2++; + x2++; + } + i2--; + x2--; + + // find start + } + } + + public void apply(int x, int y, int z) { + + } + + public void process4(int X, int Z, char[][] queues, long[][] visit) { + int xx = X << 4; + int zz = Z << 4; + + // TODO fetch instead of create + final BlockVector3[] dirs = directions; + char[][] dirQueues = new char[directions.length][]; + while (true) { + boolean empty = true; + for (int layer = 0; layer < 16; layer++) { + char[] queue = queues[layer]; + if (queue == null) continue; + char index; + while ((index = queue[0]) != queue[1]) { + queue[0]++; + + char triple = queue[index]; + int x = index & 15; + int z = (index >> 4) & 15; + int y = index >> 8; + } + queuePool.add(queue); + queues[layer] = null; + continue; + } + + if (empty) break; + } + // empty queues + +// while (indexStart != indexEnd) { +// char index = queue[indexStart++]; +// byte dirs = 0xF; +// int x = index & 15; +// int z = (index >> 4) & 15; +// int y = index >> 8; +// +// int layer = y >> 4; +// long[] visitBits = visit[layer]; +// +// int x1 = x; +// int x2 = x; +// +// // find start of scan-line +// int i1 = index; +// while (true) { +// if (x1 < 0) { +// // queue in adjacent chunk +// break; +// } +// if (get(visitBits, i1--)) break; +// x1--; +// } +// i1++; +// x1++; +// +// // find end of scan-line +// int i2 = index; +// while (true) { +// if (x2 > 15) { +// // queue in adjacent chunk +// break; +// } +// if (get(visitBits, i2++)) break; +// x2++; +// } +// i2--; +// x2--; +// +// boolean scanUp = false; +// boolean scanDown = false; +// boolean scanLeft = false; +// boolean scanRight = false; +// +// for (int i = i1; i <= i2; i++) { +// if (!scanDown && y > 0 && ) +// } +// +// for (int i=x1; i<=x2; i++) { // find scan-lines above this one +// if (!inScanLine && y>0 && ip.getPixel(i,y-1)==color) +// {push(i, y-1); inScanLine = true;} +// else if (inScanLine && y>0 && ip.getPixel(i,y-1)!=color) +// inScanLine = false; +// } +// +// inScanLine = false; +// for (int i=x1; i<=x2; i++) { // find scan-lines below this one +// if (!inScanLine && y> 6] |= (1L << (i & 0x3F)); + } + + public boolean get(long[] bits, final int i) { + return (bits[i >> 6] & (1L << (i & 0x3F))) != 0; + } + + public char getLocalIndex(int x, int y, int z) { + return (char) (x + (z << 4) + (y << 8)); + } + + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3Imp.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3Imp.java new file mode 100644 index 000000000..dd7399c64 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3Imp.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 Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.math; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.collect.ComparisonChain; +import com.sk89q.worldedit.math.transform.AffineTransform; + +import java.util.Comparator; + +/** + * An immutable 3-dimensional vector. + */ +public final class BlockVector3Imp extends BlockVector3 { + + public static final BlockVector3Imp ZERO = new BlockVector3Imp(0, 0, 0); + public static final BlockVector3Imp UNIT_X = new BlockVector3Imp(1, 0, 0); + public static final BlockVector3Imp UNIT_Y = new BlockVector3Imp(0, 1, 0); + public static final BlockVector3Imp UNIT_Z = new BlockVector3Imp(0, 0, 1); + public static final BlockVector3Imp ONE = new BlockVector3Imp(1, 1, 1); + + public static BlockVector3Imp at(double x, double y, double z) { + return at((int) Math.floor(x), (int) Math.floor(y), (int) Math.floor(z)); + } + + public static BlockVector3Imp at(int x, int y, int z) { + return new BlockVector3Imp(x, y, z); + } + + private final int x, y, z; + + /** + * Construct an instance. + * + * @param x the X coordinate + * @param y the Y coordinate + * @param z the Z coordinate + */ + protected BlockVector3Imp(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + @Override + public final int getX() { + return x; + } + + @Override + public final int getY() { + return y; + } + + @Override + public final int getZ() { + return z; + } + + @Override + public int hashCode() { + return (getX() ^ (getZ() << 12)) ^ (getY() << 24); + } + + @Override + public final BlockVector3 toImmutable() { + return this; + } + + @Override + public String toString() { + return "(" + getX() + ", " + getY() + ", " + getZ() + ")"; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableBlockVector3.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableBlockVector3.java index 88eb28a71..48296a3a6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableBlockVector3.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableBlockVector3.java @@ -1,25 +1,37 @@ package com.sk89q.worldedit.math; +import com.boydti.fawe.FaweCache; + public class MutableBlockVector3 extends BlockVector3 { - private static ThreadLocal MUTABLE_CACHE = ThreadLocal.withInitial(() -> new MutableBlockVector3()); + public static MutableBlockVector3 at(double x, double y, double z) { + return at((int) Math.floor(x), (int) Math.floor(y), (int) Math.floor(z)); + } + + public static MutableBlockVector3 at(int x, int y, int z) { + return new MutableBlockVector3(x, y, z); + } public static MutableBlockVector3 get(int x, int y, int z) { - return MUTABLE_CACHE.get().setComponents(x, y, z); + return FaweCache.MUTABLE_BLOCKVECTOR3.get().setComponents(x, y, z); } public MutableBlockVector3() {} public MutableBlockVector3(BlockVector3 other) { - super(other.getX(), other.getY(), other.getZ()); + this(other.getX(), other.getY(), other.getZ()); } public MutableBlockVector3 setComponents(BlockVector3 other) { return setComponents(other.getBlockX(), other.getBlockY(), other.getBlockZ()); } + private int x,y,z; + public MutableBlockVector3(int x, int y, int z) { - super(x, y, z); + this.x = x; + this.y = y; + this.z = z; } @Override @@ -30,6 +42,21 @@ public class MutableBlockVector3 extends BlockVector3 { return this; } + @Override + public final int getX() { + return x; + } + + @Override + public final int getY() { + return y; + } + + @Override + public final int getZ() { + return z; + } + @Override public MutableBlockVector3 mutX(double x) { this.x = (int) x; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java index d1a8e0d3e..a58cb450f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java @@ -27,13 +27,14 @@ import com.sk89q.worldedit.regions.iterator.RegionIterator; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.storage.ChunkStore; +import java.util.AbstractSet; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; -public abstract class AbstractRegion implements Region { +public abstract class AbstractRegion extends AbstractSet implements Region { protected World world; @@ -41,6 +42,11 @@ public abstract class AbstractRegion implements Region { this.world = world; } + @Override + public int size() { + return getArea(); + } + @Override public Vector3 getCenter() { return getMinimumPoint().add(getMaximumPoint()).toVector3().divide(2); @@ -100,21 +106,6 @@ public abstract class AbstractRegion implements Region { return points; } - /** - * Get the number of blocks in the region. - * - * @return number of blocks - */ - @Override - public int getArea() { - BlockVector3 min = getMinimumPoint(); - BlockVector3 max = getMaximumPoint(); - - return (max.getX() - min.getX() + 1) * - (max.getY() - min.getY() + 1) * - (max.getZ() - min.getZ() + 1); - } - /** * Get X-size. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java index 4076c6cd0..89f2c3522 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java @@ -19,12 +19,20 @@ package com.sk89q.worldedit.regions; +import com.boydti.fawe.beta.ChunkFilterBlock; +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.IChunkSet; +import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.world.World; import javax.annotation.Nullable; +import java.util.Iterator; import java.util.List; import java.util.Set; @@ -54,14 +62,23 @@ public interface Region extends Iterable, Cloneable { * * @return center point */ - Vector3 getCenter(); + default Vector3 getCenter() { + return getMinimumPoint().add(getMaximumPoint()).toVector3().divide(2); + } /** * Get the number of blocks in the region. * * @return number of blocks */ - int getArea(); + default int getArea() { + BlockVector3 min = getMinimumPoint(); + BlockVector3 max = getMaximumPoint(); + + return (max.getX() - min.getX() + 1) * + (max.getY() - min.getY() + 1) * + (max.getZ() - min.getZ() + 1); + } /** * Get X-size. @@ -128,7 +145,9 @@ public interface Region extends Iterable, Cloneable { * @param position the position * @return true if contained */ - boolean contains(BlockVector3 position); + default boolean contains(BlockVector3 position) { + return contains(position.getX(), position.getY(), position.getZ()); + } /** * Get a list of chunks. @@ -172,4 +191,63 @@ public interface Region extends Iterable, Cloneable { * @return the points. */ List polygonize(int maxPoints); + + default int getMinY() { + return getMinimumPoint().getY(); + } + + default int getMaxY() { + return getMaximumPoint().getY(); + } + + default void filter(final IChunk chunk, final Filter filter, ChunkFilterBlock block, final IChunkGet get, final IChunkSet set) { + int minSection = Math.max(0, getMinY() >> 4); + int maxSection = Math.min(15, getMaxY() >> 4); + for (int layer = minSection; layer <= maxSection; layer++) { + if (!get.hasSection(layer) || !filter.appliesLayer(chunk, layer)) return; + block = block.init(get, set, layer); + block.filter(filter, this); + } + } + + default void filter(final IChunk chunk, final Filter filter, ChunkFilterBlock block, final IChunkGet get, final IChunkSet set, final int minY, final int maxY) { + int minSection = minY >> 4; + int maxSection = maxY >> 4; + int yStart = (minY & 15); + int yEnd = (maxY & 15); + if (minSection == maxSection) { + filter(chunk, filter, block, get, set, minSection, yStart, yEnd); + return; + } + if (yStart != 0) { + filter(chunk, filter, block, get, set, minSection, yStart, 15); + minSection++; + } + if (yEnd != 15) { + filter(chunk, filter, block, get, set, minSection, 0, yEnd); + maxSection--; + } + for (int layer = minSection; layer < maxSection; layer++) { + filter(chunk, filter, block, get, set, layer); + } + return; + } + + default void filter(final IChunk chunk, final Filter filter, ChunkFilterBlock block, final IChunkGet get, final IChunkSet set, int layer) { + if (!get.hasSection(layer) || !filter.appliesLayer(chunk, layer)) return; + block = block.init(get, set, layer); + block.filter(filter); + } + + default void filter(final IChunk chunk, final Filter filter, ChunkFilterBlock block, final IChunkGet get, final IChunkSet set, int layer, int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { + if (!get.hasSection(layer) || !filter.appliesLayer(chunk, layer)) return; + block = block.init(get, set, layer); + block.filter(filter, minX, minY, minZ, maxX, maxY, maxZ); + } + + default void filter(final IChunk chunk, final Filter filter, ChunkFilterBlock block, final IChunkGet get, final IChunkSet set, int layer, int yStart, int yEnd) { + if (!get.hasSection(layer) || !filter.appliesLayer(chunk, layer)) return; + block = block.init(get, set, layer); + block.filter(filter, yStart, yEnd); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java index 9442deaca..cc1dbd954 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java @@ -19,9 +19,6 @@ package com.sk89q.worldedit.regions; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - import com.google.common.collect.Iterators; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.World; @@ -31,6 +28,9 @@ import java.util.Collections; 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. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/TransformRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/TransformRegion.java deleted file mode 100644 index 911e40b8b..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/TransformRegion.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.regions; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.sk89q.worldedit.math.BlockVector2; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.math.Vector3; -import com.sk89q.worldedit.math.transform.Identity; -import com.sk89q.worldedit.math.transform.Transform; -import com.sk89q.worldedit.world.World; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import javax.annotation.Nullable; - -/** - * Transforms another region according to a provided vector {@code Transform}. - * - * @see Transform - */ -public class TransformRegion extends AbstractRegion { - - private final Region region; - private Transform transform = new Identity(); - - /** - * Create a new instance. - * - * @param region the region - * @param transform the transform - */ - public TransformRegion(Region region, Transform transform) { - this(null, region, transform); - } - - /** - * Create a new instance. - * - * @param world the world, which may be null - * @param region the region - * @param transform the transform - */ - public TransformRegion(@Nullable World world, Region region, Transform transform) { - super(world); - checkNotNull(region); - checkNotNull(transform); - this.region = region; - this.transform = transform; - } - - /** - * Get the untransformed, base region. - * - * @return the base region - */ - public Region getRegion() { - return region; - } - - /** - * Get the transform that is applied. - * - * @return the transform - */ - public Transform getTransform() { - return transform; - } - - /** - * Set the transform that is applied. - * - * @param transform the transform - */ - public void setTransform(Transform transform) { - checkNotNull(transform); - this.transform = transform; - } - - @Override - public BlockVector3 getMinimumPoint() { - return transform.apply(region.getMinimumPoint().toVector3()).toBlockPoint(); - } - - @Override - public BlockVector3 getMaximumPoint() { - return transform.apply(region.getMaximumPoint().toVector3()).toBlockPoint(); - } - - @Override - public Vector3 getCenter() { - return transform.apply(region.getCenter()); - } - - @Override - public int getArea() { - return region.getArea(); // Cannot transform this - } - - @Override - public int getWidth() { - return getMaximumPoint().subtract(getMinimumPoint()).getBlockX() + 1; - } - - @Override - public int getHeight() { - return getMaximumPoint().subtract(getMinimumPoint()).getBlockY() + 1; - } - - @Override - public int getLength() { - return getMaximumPoint().subtract(getMinimumPoint()).getBlockZ() + 1; - } - - @Override - public void expand(BlockVector3... changes) throws RegionOperationException { - throw new RegionOperationException("Can't expand a TransformedRegion"); - } - - @Override - public void contract(BlockVector3... changes) throws RegionOperationException { - throw new RegionOperationException("Can't contract a TransformedRegion"); - } - - @Override - public void shift(BlockVector3 change) throws RegionOperationException { - throw new RegionOperationException("Can't change a TransformedRegion"); - } - - @Override - public boolean contains(BlockVector3 position) { - return region.contains(transform.inverse().apply(position.toVector3()).toBlockPoint()); - } - - @Override - public List polygonize(int maxPoints) { - List origPoints = region.polygonize(maxPoints); - List transformedPoints = new ArrayList<>(); - for (BlockVector2 vector : origPoints) { - transformedPoints.add(transform.apply(vector.toVector3(0)).toVector2().toBlockPoint()); - } - return transformedPoints; - } - - @Override - public Iterator iterator() { - final Iterator it = region.iterator(); - - return new Iterator() { - @Override - public boolean hasNext() { - return it.hasNext(); - } - - @Override - public BlockVector3 next() { - BlockVector3 next = it.next(); - if (next != null) { - return transform.apply(next.toVector3()).toBlockPoint(); - } else { - return null; - } - } - - @Override - public void remove() { - it.remove(); - } - }; - } -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/state/PropertyKey.java b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/state/PropertyKey.java index ef6c77d24..34f941ae0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/state/PropertyKey.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/state/PropertyKey.java @@ -6,6 +6,7 @@ import com.sk89q.util.ReflectionUtil; import com.sk89q.worldedit.world.block.BlockTypes; import java.util.HashMap; +import java.util.Locale; import java.util.Map; /** @@ -100,7 +101,7 @@ public enum PropertyKey { PropertyKey property = PropertyKey.get(id); if (property == null) { Fawe.debug("Registering property " + id); - property = ReflectionUtils.addEnum(PropertyKey.class, id.toUpperCase()); + property = ReflectionUtils.addEnum(PropertyKey.class, id.toUpperCase(Locale.ROOT)); if (property.getId() == null) { try { ReflectionUtils.setFailsafeFieldValue(PropertyKey.class.getDeclaredField("id"), property, property.name().toLowerCase()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/RequestSelection.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/RequestSelection.java index 9e37e4da0..7645154f8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/RequestSelection.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/RequestSelection.java @@ -23,6 +23,7 @@ import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.regions.NullRegion; import com.sk89q.worldedit.regions.Region; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/SimpleDispatcher.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/SimpleDispatcher.java index bc634c06f..5677a79bb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/SimpleDispatcher.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/SimpleDispatcher.java @@ -35,6 +35,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -104,12 +105,12 @@ public class SimpleDispatcher implements Dispatcher { @Override public boolean contains(String alias) { - return commands.containsKey(alias.toLowerCase()); + return commands.containsKey(alias.toLowerCase(Locale.ROOT)); } @Override public CommandMapping get(String alias) { - return commands.get(alias.toLowerCase()); + return commands.get(alias.toLowerCase(Locale.ROOT)); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentUtils.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentUtils.java index 22141fedd..259853571 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentUtils.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentUtils.java @@ -23,6 +23,7 @@ import com.google.common.collect.Lists; import java.util.Collection; import java.util.List; +import java.util.Locale; public final class ArgumentUtils { @@ -35,7 +36,7 @@ public final class ArgumentUtils { } List suggestions = Lists.newArrayList(); for (String item : items) { - if (item.toLowerCase().startsWith(s)) { + if (item.toLowerCase(Locale.ROOT).startsWith(s)) { suggestions.add(item); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/BranchingCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/BranchingCommand.java index ce4ba58fe..6ffe01174 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/BranchingCommand.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/BranchingCommand.java @@ -30,6 +30,7 @@ import com.sk89q.worldedit.util.command.argument.CommandArgs; import com.sk89q.worldedit.util.command.argument.MissingArgumentException; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -55,7 +56,7 @@ public abstract class BranchingCommand implements CommandExecutor { public T call(CommandArgs args, CommandLocals locals) throws CommandException { try { String classifier = args.next(); - CommandExecutor executor = options.get(classifier.toLowerCase()); + CommandExecutor executor = options.get(classifier.toLowerCase(Locale.ROOT)); if (executor != null) { return executor.call(args, locals); } else { @@ -72,7 +73,7 @@ public abstract class BranchingCommand implements CommandExecutor { public List getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException { String classifier = args.next(); try { - CommandExecutor executor = options.get(classifier.toLowerCase()); + CommandExecutor executor = options.get(classifier.toLowerCase(Locale.ROOT)); if (executor != null) { return executor.getSuggestions(args, locals); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricCallable.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricCallable.java index c17282aca..bb0e76b80 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricCallable.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricCallable.java @@ -43,6 +43,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Set; /** @@ -348,10 +349,10 @@ public class ParametricCallable extends AParametricCallable { */ private static String generateName(Type type, Annotation classifier, int index) { if (classifier != null) { - return classifier.annotationType().getSimpleName().toLowerCase(); + return classifier.annotationType().getSimpleName().toLowerCase(Locale.ROOT); } else { if (type instanceof Class) { - return ((Class) type).getSimpleName().toLowerCase(); + return ((Class) type).getSimpleName().toLowerCase(Locale.ROOT); } else { return "unknown" + index; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/IncendoPaste.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/IncendoPaste.java index c81c3417c..2b10ad132 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/IncendoPaste.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/IncendoPaste.java @@ -45,7 +45,7 @@ public final class IncendoPaste implements Paster{ if (pasteApplication == null || pasteApplication.isEmpty()) { throw new IllegalArgumentException("paste application cannot be null, nor empty"); } - if (!VALID_APPLICATIONS.contains(pasteApplication.toLowerCase(Locale.ENGLISH))) { + if (!VALID_APPLICATIONS.contains(pasteApplication.toLowerCase(Locale.ROOT))) { throw new IllegalArgumentException( String.format("Unknown application name: %s", pasteApplication)); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java index c3ef611d8..ff1ac5edc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java @@ -81,12 +81,12 @@ public class NullWorld extends AbstractWorld { } @Override - public BiomeType getBiome(BlockVector2 position) { + public BiomeType getBiomeType(int x, int z) { return BiomeTypes.THE_VOID; } @Override - public boolean setBiome(BlockVector2 position, BiomeType biome) { + public boolean setBiome(int x, int y, int z, BiomeType biome) { return false; } @@ -132,13 +132,18 @@ public class NullWorld extends AbstractWorld { } @Override - public BlockState getBlock(BlockVector3 position) { + public BlockState getBlock(int x, int y, int z) { return BlockTypes.AIR.getDefaultState(); } @Override - public BlockState getLazyBlock(BlockVector3 position) { - return getBlock(position); + public BaseBlock getFullBlock(int x, int y, int z) { + return BlockTypes.AIR.getDefaultState().toBaseBlock(); + } + + @Override + public > boolean setBlock(int x, int y, int z, T block) throws WorldEditException { + return false; } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java index 471279281..26858d7a2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java @@ -67,6 +67,7 @@ public interface World extends Extent { * * @return the maximum Y */ + @Override int getMaxY(); /** @@ -106,7 +107,9 @@ public interface World extends Extent { * @param notifyAndLight true to to notify and light * @return true if the block was successfully set (return value may not be accurate) */ - > boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws WorldEditException; + default > boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws WorldEditException { + return setBlock(position, block); + } /** * Notifies the simulation that the block at the given location has diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockID.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockID.java index 82f5c2979..278e091cb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockID.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockID.java @@ -3,571 +3,648 @@ package com.sk89q.worldedit.world.block; public class BlockID { // Used for switch statements on blocks public static final int __RESERVED__ = 0; - public static final int ACACIA_BUTTON = 1; - public static final int ACACIA_DOOR = 2; - public static final int ACACIA_FENCE = 3; - public static final int ACACIA_FENCE_GATE = 4; - public static final int ACACIA_LEAVES = 5; - public static final int ACACIA_LOG = 6; - public static final int ACACIA_PLANKS = 7; - public static final int ACACIA_PRESSURE_PLATE = 8; - public static final int ACACIA_SAPLING = 9; - public static final int ACACIA_SLAB = 10; - public static final int ACACIA_STAIRS = 11; - public static final int ACACIA_TRAPDOOR = 12; - public static final int ACACIA_WOOD = 13; - public static final int ACTIVATOR_RAIL = 14; - public static final int AIR = 15; - public static final int ALLIUM = 16; - public static final int ANDESITE = 17; - public static final int ANVIL = 18; - public static final int ATTACHED_MELON_STEM = 19; - public static final int ATTACHED_PUMPKIN_STEM = 20; - public static final int AZURE_BLUET = 21; - public static final int BARRIER = 22; - public static final int BEACON = 23; - public static final int BEDROCK = 24; - public static final int BEETROOTS = 25; - public static final int BIRCH_BUTTON = 26; - public static final int BIRCH_DOOR = 27; - public static final int BIRCH_FENCE = 28; - public static final int BIRCH_FENCE_GATE = 29; - public static final int BIRCH_LEAVES = 30; - public static final int BIRCH_LOG = 31; - public static final int BIRCH_PLANKS = 32; - public static final int BIRCH_PRESSURE_PLATE = 33; - public static final int BIRCH_SAPLING = 34; - public static final int BIRCH_SLAB = 35; - public static final int BIRCH_STAIRS = 36; - public static final int BIRCH_TRAPDOOR = 37; - public static final int BIRCH_WOOD = 38; - public static final int BLACK_BANNER = 39; - public static final int BLACK_BED = 40; - public static final int BLACK_CARPET = 41; - public static final int BLACK_CONCRETE = 42; - public static final int BLACK_CONCRETE_POWDER = 43; - public static final int BLACK_GLAZED_TERRACOTTA = 44; - public static final int BLACK_SHULKER_BOX = 45; - public static final int BLACK_STAINED_GLASS = 46; - public static final int BLACK_STAINED_GLASS_PANE = 47; - public static final int BLACK_TERRACOTTA = 48; - public static final int BLACK_WALL_BANNER = 49; - public static final int BLACK_WOOL = 50; - public static final int BLUE_BANNER = 51; - public static final int BLUE_BED = 52; - public static final int BLUE_CARPET = 53; - public static final int BLUE_CONCRETE = 54; - public static final int BLUE_CONCRETE_POWDER = 55; - public static final int BLUE_GLAZED_TERRACOTTA = 56; - public static final int BLUE_ICE = 57; - public static final int BLUE_ORCHID = 58; - public static final int BLUE_SHULKER_BOX = 59; - public static final int BLUE_STAINED_GLASS = 60; - public static final int BLUE_STAINED_GLASS_PANE = 61; - public static final int BLUE_TERRACOTTA = 62; - public static final int BLUE_WALL_BANNER = 63; - public static final int BLUE_WOOL = 64; - public static final int BONE_BLOCK = 65; - public static final int BOOKSHELF = 66; - public static final int BRAIN_CORAL = 67; - public static final int BRAIN_CORAL_BLOCK = 68; - public static final int BRAIN_CORAL_FAN = 69; - public static final int BRAIN_CORAL_WALL_FAN = 70; - public static final int BREWING_STAND = 71; - public static final int BRICK_SLAB = 72; - public static final int BRICK_STAIRS = 73; - public static final int BRICKS = 74; - public static final int BROWN_BANNER = 75; - public static final int BROWN_BED = 76; - public static final int BROWN_CARPET = 77; - public static final int BROWN_CONCRETE = 78; - public static final int BROWN_CONCRETE_POWDER = 79; - public static final int BROWN_GLAZED_TERRACOTTA = 80; - public static final int BROWN_MUSHROOM = 81; - public static final int BROWN_MUSHROOM_BLOCK = 82; - public static final int BROWN_SHULKER_BOX = 83; - public static final int BROWN_STAINED_GLASS = 84; - public static final int BROWN_STAINED_GLASS_PANE = 85; - public static final int BROWN_TERRACOTTA = 86; - public static final int BROWN_WALL_BANNER = 87; - public static final int BROWN_WOOL = 88; - public static final int BUBBLE_COLUMN = 89; - public static final int BUBBLE_CORAL = 90; - public static final int BUBBLE_CORAL_BLOCK = 91; - public static final int BUBBLE_CORAL_FAN = 92; - public static final int BUBBLE_CORAL_WALL_FAN = 93; - public static final int CACTUS = 94; - public static final int CAKE = 95; - public static final int CARROTS = 96; - public static final int CARVED_PUMPKIN = 97; - public static final int CAULDRON = 98; - public static final int CAVE_AIR = 99; - public static final int CHAIN_COMMAND_BLOCK = 100; - public static final int CHEST = 101; - public static final int CHIPPED_ANVIL = 102; - public static final int CHISELED_QUARTZ_BLOCK = 103; - public static final int CHISELED_RED_SANDSTONE = 104; - public static final int CHISELED_SANDSTONE = 105; - public static final int CHISELED_STONE_BRICKS = 106; - public static final int CHORUS_FLOWER = 107; - public static final int CHORUS_PLANT = 108; - public static final int CLAY = 109; - public static final int COAL_BLOCK = 110; - public static final int COAL_ORE = 111; - public static final int COARSE_DIRT = 112; - public static final int COBBLESTONE = 113; - public static final int COBBLESTONE_SLAB = 114; - public static final int COBBLESTONE_STAIRS = 115; - public static final int COBBLESTONE_WALL = 116; - public static final int COBWEB = 117; - public static final int COCOA = 118; - public static final int COMMAND_BLOCK = 119; - public static final int COMPARATOR = 120; - public static final int CONDUIT = 121; - public static final int CRACKED_STONE_BRICKS = 122; - public static final int CRAFTING_TABLE = 123; - public static final int CREEPER_HEAD = 124; - public static final int CREEPER_WALL_HEAD = 125; - public static final int CUT_RED_SANDSTONE = 126; - public static final int CUT_SANDSTONE = 127; - public static final int CYAN_BANNER = 128; - public static final int CYAN_BED = 129; - public static final int CYAN_CARPET = 130; - public static final int CYAN_CONCRETE = 131; - public static final int CYAN_CONCRETE_POWDER = 132; - public static final int CYAN_GLAZED_TERRACOTTA = 133; - public static final int CYAN_SHULKER_BOX = 134; - public static final int CYAN_STAINED_GLASS = 135; - public static final int CYAN_STAINED_GLASS_PANE = 136; - public static final int CYAN_TERRACOTTA = 137; - public static final int CYAN_WALL_BANNER = 138; - public static final int CYAN_WOOL = 139; - public static final int DAMAGED_ANVIL = 140; - public static final int DANDELION = 141; - public static final int DARK_OAK_BUTTON = 142; - public static final int DARK_OAK_DOOR = 143; - public static final int DARK_OAK_FENCE = 144; - public static final int DARK_OAK_FENCE_GATE = 145; - public static final int DARK_OAK_LEAVES = 146; - public static final int DARK_OAK_LOG = 147; - public static final int DARK_OAK_PLANKS = 148; - public static final int DARK_OAK_PRESSURE_PLATE = 149; - public static final int DARK_OAK_SAPLING = 150; - public static final int DARK_OAK_SLAB = 151; - public static final int DARK_OAK_STAIRS = 152; - public static final int DARK_OAK_TRAPDOOR = 153; - public static final int DARK_OAK_WOOD = 154; - public static final int DARK_PRISMARINE = 155; - public static final int DARK_PRISMARINE_SLAB = 156; - public static final int DARK_PRISMARINE_STAIRS = 157; - public static final int DAYLIGHT_DETECTOR = 158; - public static final int DEAD_BRAIN_CORAL = 159; - public static final int DEAD_BRAIN_CORAL_BLOCK = 160; - public static final int DEAD_BRAIN_CORAL_FAN = 161; - public static final int DEAD_BRAIN_CORAL_WALL_FAN = 162; - public static final int DEAD_BUBBLE_CORAL = 163; - public static final int DEAD_BUBBLE_CORAL_BLOCK = 164; - public static final int DEAD_BUBBLE_CORAL_FAN = 165; - public static final int DEAD_BUBBLE_CORAL_WALL_FAN = 166; - public static final int DEAD_BUSH = 167; - public static final int DEAD_FIRE_CORAL = 168; - public static final int DEAD_FIRE_CORAL_BLOCK = 169; - public static final int DEAD_FIRE_CORAL_FAN = 170; - public static final int DEAD_FIRE_CORAL_WALL_FAN = 171; - public static final int DEAD_HORN_CORAL = 172; - public static final int DEAD_HORN_CORAL_BLOCK = 173; - public static final int DEAD_HORN_CORAL_FAN = 174; - public static final int DEAD_HORN_CORAL_WALL_FAN = 175; - public static final int DEAD_TUBE_CORAL = 176; - public static final int DEAD_TUBE_CORAL_BLOCK = 177; - public static final int DEAD_TUBE_CORAL_FAN = 178; - public static final int DEAD_TUBE_CORAL_WALL_FAN = 179; - public static final int DETECTOR_RAIL = 180; - public static final int DIAMOND_BLOCK = 181; - public static final int DIAMOND_ORE = 182; - public static final int DIORITE = 183; - public static final int DIRT = 184; - public static final int DISPENSER = 185; - public static final int DRAGON_EGG = 186; - public static final int DRAGON_HEAD = 187; - public static final int DRAGON_WALL_HEAD = 188; - public static final int DRIED_KELP_BLOCK = 189; - public static final int DROPPER = 190; - public static final int EMERALD_BLOCK = 191; - public static final int EMERALD_ORE = 192; - public static final int ENCHANTING_TABLE = 193; - public static final int END_GATEWAY = 194; - public static final int END_PORTAL = 195; - public static final int END_PORTAL_FRAME = 196; - public static final int END_ROD = 197; - public static final int END_STONE = 198; - public static final int END_STONE_BRICKS = 199; - public static final int ENDER_CHEST = 200; - public static final int FARMLAND = 201; - public static final int FERN = 202; - public static final int FIRE = 203; - public static final int FIRE_CORAL = 204; - public static final int FIRE_CORAL_BLOCK = 205; - public static final int FIRE_CORAL_FAN = 206; - public static final int FIRE_CORAL_WALL_FAN = 207; - public static final int FLOWER_POT = 208; - public static final int FROSTED_ICE = 209; - public static final int FURNACE = 210; - public static final int GLASS = 211; - public static final int GLASS_PANE = 212; - public static final int GLOWSTONE = 213; - public static final int GOLD_BLOCK = 214; - public static final int GOLD_ORE = 215; - public static final int GRANITE = 216; - public static final int GRASS = 217; - public static final int GRASS_BLOCK = 218; - public static final int GRASS_PATH = 219; - public static final int GRAVEL = 220; - public static final int GRAY_BANNER = 221; - public static final int GRAY_BED = 222; - public static final int GRAY_CARPET = 223; - public static final int GRAY_CONCRETE = 224; - public static final int GRAY_CONCRETE_POWDER = 225; - public static final int GRAY_GLAZED_TERRACOTTA = 226; - public static final int GRAY_SHULKER_BOX = 227; - public static final int GRAY_STAINED_GLASS = 228; - public static final int GRAY_STAINED_GLASS_PANE = 229; - public static final int GRAY_TERRACOTTA = 230; - public static final int GRAY_WALL_BANNER = 231; - public static final int GRAY_WOOL = 232; - public static final int GREEN_BANNER = 233; - public static final int GREEN_BED = 234; - public static final int GREEN_CARPET = 235; - public static final int GREEN_CONCRETE = 236; - public static final int GREEN_CONCRETE_POWDER = 237; - public static final int GREEN_GLAZED_TERRACOTTA = 238; - public static final int GREEN_SHULKER_BOX = 239; - public static final int GREEN_STAINED_GLASS = 240; - public static final int GREEN_STAINED_GLASS_PANE = 241; - public static final int GREEN_TERRACOTTA = 242; - public static final int GREEN_WALL_BANNER = 243; - public static final int GREEN_WOOL = 244; - public static final int HAY_BLOCK = 245; - public static final int HEAVY_WEIGHTED_PRESSURE_PLATE = 246; - public static final int HOPPER = 247; - public static final int HORN_CORAL = 248; - public static final int HORN_CORAL_BLOCK = 249; - public static final int HORN_CORAL_FAN = 250; - public static final int HORN_CORAL_WALL_FAN = 251; - public static final int ICE = 252; - public static final int INFESTED_CHISELED_STONE_BRICKS = 253; - public static final int INFESTED_COBBLESTONE = 254; - public static final int INFESTED_CRACKED_STONE_BRICKS = 255; - public static final int INFESTED_MOSSY_STONE_BRICKS = 256; - public static final int INFESTED_STONE = 257; - public static final int INFESTED_STONE_BRICKS = 258; - public static final int IRON_BARS = 259; - public static final int IRON_BLOCK = 260; - public static final int IRON_DOOR = 261; - public static final int IRON_ORE = 262; - public static final int IRON_TRAPDOOR = 263; - public static final int JACK_O_LANTERN = 264; - public static final int JUKEBOX = 265; - public static final int JUNGLE_BUTTON = 266; - public static final int JUNGLE_DOOR = 267; - public static final int JUNGLE_FENCE = 268; - public static final int JUNGLE_FENCE_GATE = 269; - public static final int JUNGLE_LEAVES = 270; - public static final int JUNGLE_LOG = 271; - public static final int JUNGLE_PLANKS = 272; - public static final int JUNGLE_PRESSURE_PLATE = 273; - public static final int JUNGLE_SAPLING = 274; - public static final int JUNGLE_SLAB = 275; - public static final int JUNGLE_STAIRS = 276; - public static final int JUNGLE_TRAPDOOR = 277; - public static final int JUNGLE_WOOD = 278; - public static final int KELP = 279; - public static final int KELP_PLANT = 280; - public static final int LADDER = 281; - public static final int LAPIS_BLOCK = 282; - public static final int LAPIS_ORE = 283; - public static final int LARGE_FERN = 284; - public static final int LAVA = 285; - public static final int LEVER = 286; - public static final int LIGHT_BLUE_BANNER = 287; - public static final int LIGHT_BLUE_BED = 288; - public static final int LIGHT_BLUE_CARPET = 289; - public static final int LIGHT_BLUE_CONCRETE = 290; - public static final int LIGHT_BLUE_CONCRETE_POWDER = 291; - public static final int LIGHT_BLUE_GLAZED_TERRACOTTA = 292; - public static final int LIGHT_BLUE_SHULKER_BOX = 293; - public static final int LIGHT_BLUE_STAINED_GLASS = 294; - public static final int LIGHT_BLUE_STAINED_GLASS_PANE = 295; - public static final int LIGHT_BLUE_TERRACOTTA = 296; - public static final int LIGHT_BLUE_WALL_BANNER = 297; - public static final int LIGHT_BLUE_WOOL = 298; - public static final int LIGHT_GRAY_BANNER = 299; - public static final int LIGHT_GRAY_BED = 300; - public static final int LIGHT_GRAY_CARPET = 301; - public static final int LIGHT_GRAY_CONCRETE = 302; - public static final int LIGHT_GRAY_CONCRETE_POWDER = 303; - public static final int LIGHT_GRAY_GLAZED_TERRACOTTA = 304; - public static final int LIGHT_GRAY_SHULKER_BOX = 305; - public static final int LIGHT_GRAY_STAINED_GLASS = 306; - public static final int LIGHT_GRAY_STAINED_GLASS_PANE = 307; - public static final int LIGHT_GRAY_TERRACOTTA = 308; - public static final int LIGHT_GRAY_WALL_BANNER = 309; - public static final int LIGHT_GRAY_WOOL = 310; - public static final int LIGHT_WEIGHTED_PRESSURE_PLATE = 311; - public static final int LILAC = 312; - public static final int LILY_PAD = 313; - public static final int LIME_BANNER = 314; - public static final int LIME_BED = 315; - public static final int LIME_CARPET = 316; - public static final int LIME_CONCRETE = 317; - public static final int LIME_CONCRETE_POWDER = 318; - public static final int LIME_GLAZED_TERRACOTTA = 319; - public static final int LIME_SHULKER_BOX = 320; - public static final int LIME_STAINED_GLASS = 321; - public static final int LIME_STAINED_GLASS_PANE = 322; - public static final int LIME_TERRACOTTA = 323; - public static final int LIME_WALL_BANNER = 324; - public static final int LIME_WOOL = 325; - public static final int MAGENTA_BANNER = 326; - public static final int MAGENTA_BED = 327; - public static final int MAGENTA_CARPET = 328; - public static final int MAGENTA_CONCRETE = 329; - public static final int MAGENTA_CONCRETE_POWDER = 330; - public static final int MAGENTA_GLAZED_TERRACOTTA = 331; - public static final int MAGENTA_SHULKER_BOX = 332; - public static final int MAGENTA_STAINED_GLASS = 333; - public static final int MAGENTA_STAINED_GLASS_PANE = 334; - public static final int MAGENTA_TERRACOTTA = 335; - public static final int MAGENTA_WALL_BANNER = 336; - public static final int MAGENTA_WOOL = 337; - public static final int MAGMA_BLOCK = 338; - public static final int MELON = 339; - public static final int MELON_STEM = 340; - public static final int MOSSY_COBBLESTONE = 341; - public static final int MOSSY_COBBLESTONE_WALL = 342; - public static final int MOSSY_STONE_BRICKS = 343; - public static final int MOVING_PISTON = 344; - public static final int MUSHROOM_STEM = 345; - public static final int MYCELIUM = 346; - public static final int NETHER_BRICK_FENCE = 347; - public static final int NETHER_BRICK_SLAB = 348; - public static final int NETHER_BRICK_STAIRS = 349; - public static final int NETHER_BRICKS = 350; - public static final int NETHER_PORTAL = 351; - public static final int NETHER_QUARTZ_ORE = 352; - public static final int NETHER_WART = 353; - public static final int NETHER_WART_BLOCK = 354; - public static final int NETHERRACK = 355; - public static final int NOTE_BLOCK = 356; - public static final int OAK_BUTTON = 357; - public static final int OAK_DOOR = 358; - public static final int OAK_FENCE = 359; - public static final int OAK_FENCE_GATE = 360; - public static final int OAK_LEAVES = 361; - public static final int OAK_LOG = 362; - public static final int OAK_PLANKS = 363; - public static final int OAK_PRESSURE_PLATE = 364; - public static final int OAK_SAPLING = 365; - public static final int OAK_SLAB = 366; - public static final int OAK_STAIRS = 367; - public static final int OAK_TRAPDOOR = 368; - public static final int OAK_WOOD = 369; - public static final int OBSERVER = 370; - public static final int OBSIDIAN = 371; - public static final int ORANGE_BANNER = 372; - public static final int ORANGE_BED = 373; - public static final int ORANGE_CARPET = 374; - public static final int ORANGE_CONCRETE = 375; - public static final int ORANGE_CONCRETE_POWDER = 376; - public static final int ORANGE_GLAZED_TERRACOTTA = 377; - public static final int ORANGE_SHULKER_BOX = 378; - public static final int ORANGE_STAINED_GLASS = 379; - public static final int ORANGE_STAINED_GLASS_PANE = 380; - public static final int ORANGE_TERRACOTTA = 381; - public static final int ORANGE_TULIP = 382; - public static final int ORANGE_WALL_BANNER = 383; - public static final int ORANGE_WOOL = 384; - public static final int OXEYE_DAISY = 385; - public static final int PACKED_ICE = 386; - public static final int PEONY = 387; - public static final int PETRIFIED_OAK_SLAB = 388; - public static final int PINK_BANNER = 389; - public static final int PINK_BED = 390; - public static final int PINK_CARPET = 391; - public static final int PINK_CONCRETE = 392; - public static final int PINK_CONCRETE_POWDER = 393; - public static final int PINK_GLAZED_TERRACOTTA = 394; - public static final int PINK_SHULKER_BOX = 395; - public static final int PINK_STAINED_GLASS = 396; - public static final int PINK_STAINED_GLASS_PANE = 397; - public static final int PINK_TERRACOTTA = 398; - public static final int PINK_TULIP = 399; - public static final int PINK_WALL_BANNER = 400; - public static final int PINK_WOOL = 401; - public static final int PISTON = 402; - public static final int PISTON_HEAD = 403; - public static final int PLAYER_HEAD = 404; - public static final int PLAYER_WALL_HEAD = 405; - public static final int PODZOL = 406; - public static final int POLISHED_ANDESITE = 407; - public static final int POLISHED_DIORITE = 408; - public static final int POLISHED_GRANITE = 409; - public static final int POPPY = 410; - public static final int POTATOES = 411; - public static final int POTTED_ACACIA_SAPLING = 412; - public static final int POTTED_ALLIUM = 413; - public static final int POTTED_AZURE_BLUET = 414; - public static final int POTTED_BIRCH_SAPLING = 415; - public static final int POTTED_BLUE_ORCHID = 416; - public static final int POTTED_BROWN_MUSHROOM = 417; - public static final int POTTED_CACTUS = 418; - public static final int POTTED_DANDELION = 419; - public static final int POTTED_DARK_OAK_SAPLING = 420; - public static final int POTTED_DEAD_BUSH = 421; - public static final int POTTED_FERN = 422; - public static final int POTTED_JUNGLE_SAPLING = 423; - public static final int POTTED_OAK_SAPLING = 424; - public static final int POTTED_ORANGE_TULIP = 425; - public static final int POTTED_OXEYE_DAISY = 426; - public static final int POTTED_PINK_TULIP = 427; - public static final int POTTED_POPPY = 428; - public static final int POTTED_RED_MUSHROOM = 429; - public static final int POTTED_RED_TULIP = 430; - public static final int POTTED_SPRUCE_SAPLING = 431; - public static final int POTTED_WHITE_TULIP = 432; - public static final int POWERED_RAIL = 433; - public static final int PRISMARINE = 434; - public static final int PRISMARINE_BRICK_SLAB = 435; - public static final int PRISMARINE_BRICK_STAIRS = 436; - public static final int PRISMARINE_BRICKS = 437; - public static final int PRISMARINE_SLAB = 438; - public static final int PRISMARINE_STAIRS = 439; - public static final int PUMPKIN = 440; - public static final int PUMPKIN_STEM = 441; - public static final int PURPLE_BANNER = 442; - public static final int PURPLE_BED = 443; - public static final int PURPLE_CARPET = 444; - public static final int PURPLE_CONCRETE = 445; - public static final int PURPLE_CONCRETE_POWDER = 446; - public static final int PURPLE_GLAZED_TERRACOTTA = 447; - public static final int PURPLE_SHULKER_BOX = 448; - public static final int PURPLE_STAINED_GLASS = 449; - public static final int PURPLE_STAINED_GLASS_PANE = 450; - public static final int PURPLE_TERRACOTTA = 451; - public static final int PURPLE_WALL_BANNER = 452; - public static final int PURPLE_WOOL = 453; - public static final int PURPUR_BLOCK = 454; - public static final int PURPUR_PILLAR = 455; - public static final int PURPUR_SLAB = 456; - public static final int PURPUR_STAIRS = 457; - public static final int QUARTZ_BLOCK = 458; - public static final int QUARTZ_PILLAR = 459; - public static final int QUARTZ_SLAB = 460; - public static final int QUARTZ_STAIRS = 461; - public static final int RAIL = 462; - public static final int RED_BANNER = 463; - public static final int RED_BED = 464; - public static final int RED_CARPET = 465; - public static final int RED_CONCRETE = 466; - public static final int RED_CONCRETE_POWDER = 467; - public static final int RED_GLAZED_TERRACOTTA = 468; - public static final int RED_MUSHROOM = 469; - public static final int RED_MUSHROOM_BLOCK = 470; - public static final int RED_NETHER_BRICKS = 471; - public static final int RED_SAND = 472; - public static final int RED_SANDSTONE = 473; - public static final int RED_SANDSTONE_SLAB = 474; - public static final int RED_SANDSTONE_STAIRS = 475; - public static final int RED_SHULKER_BOX = 476; - public static final int RED_STAINED_GLASS = 477; - public static final int RED_STAINED_GLASS_PANE = 478; - public static final int RED_TERRACOTTA = 479; - public static final int RED_TULIP = 480; - public static final int RED_WALL_BANNER = 481; - public static final int RED_WOOL = 482; - public static final int REDSTONE_BLOCK = 483; - public static final int REDSTONE_LAMP = 484; - public static final int REDSTONE_ORE = 485; - public static final int REDSTONE_TORCH = 486; - public static final int REDSTONE_WALL_TORCH = 487; - public static final int REDSTONE_WIRE = 488; - public static final int REPEATER = 489; - public static final int REPEATING_COMMAND_BLOCK = 490; - public static final int ROSE_BUSH = 491; - public static final int SAND = 492; - public static final int SANDSTONE = 493; - public static final int SANDSTONE_SLAB = 494; - public static final int SANDSTONE_STAIRS = 495; - public static final int SEA_LANTERN = 496; - public static final int SEA_PICKLE = 497; - public static final int SEAGRASS = 498; - public static final int SHULKER_BOX = 499; - public static final int SIGN = 500; - public static final int SKELETON_SKULL = 501; - public static final int SKELETON_WALL_SKULL = 502; - public static final int SLIME_BLOCK = 503; - public static final int SMOOTH_QUARTZ = 504; - public static final int SMOOTH_RED_SANDSTONE = 505; - public static final int SMOOTH_SANDSTONE = 506; - public static final int SMOOTH_STONE = 507; - public static final int SNOW = 508; - public static final int SNOW_BLOCK = 509; - public static final int SOUL_SAND = 510; - public static final int SPAWNER = 511; - public static final int SPONGE = 512; - public static final int SPRUCE_BUTTON = 513; - public static final int SPRUCE_DOOR = 514; - public static final int SPRUCE_FENCE = 515; - public static final int SPRUCE_FENCE_GATE = 516; - public static final int SPRUCE_LEAVES = 517; - public static final int SPRUCE_LOG = 518; - public static final int SPRUCE_PLANKS = 519; - public static final int SPRUCE_PRESSURE_PLATE = 520; - public static final int SPRUCE_SAPLING = 521; - public static final int SPRUCE_SLAB = 522; - public static final int SPRUCE_STAIRS = 523; - public static final int SPRUCE_TRAPDOOR = 524; - public static final int SPRUCE_WOOD = 525; - public static final int STICKY_PISTON = 526; - public static final int STONE = 527; - public static final int STONE_BRICK_SLAB = 528; - public static final int STONE_BRICK_STAIRS = 529; - public static final int STONE_BRICKS = 530; - public static final int STONE_BUTTON = 531; - public static final int STONE_PRESSURE_PLATE = 532; - public static final int STONE_SLAB = 533; - public static final int STRIPPED_ACACIA_LOG = 534; - public static final int STRIPPED_ACACIA_WOOD = 535; - public static final int STRIPPED_BIRCH_LOG = 536; - public static final int STRIPPED_BIRCH_WOOD = 537; - public static final int STRIPPED_DARK_OAK_LOG = 538; - public static final int STRIPPED_DARK_OAK_WOOD = 539; - public static final int STRIPPED_JUNGLE_LOG = 540; - public static final int STRIPPED_JUNGLE_WOOD = 541; - public static final int STRIPPED_OAK_LOG = 542; - public static final int STRIPPED_OAK_WOOD = 543; - public static final int STRIPPED_SPRUCE_LOG = 544; - public static final int STRIPPED_SPRUCE_WOOD = 545; - public static final int STRUCTURE_BLOCK = 546; - public static final int STRUCTURE_VOID = 547; - public static final int SUGAR_CANE = 548; - public static final int SUNFLOWER = 549; - public static final int TALL_GRASS = 550; - public static final int TALL_SEAGRASS = 551; - public static final int TERRACOTTA = 552; - public static final int TNT = 553; - public static final int TORCH = 554; - public static final int TRAPPED_CHEST = 555; - public static final int TRIPWIRE = 556; - public static final int TRIPWIRE_HOOK = 557; - public static final int TUBE_CORAL = 558; - public static final int TUBE_CORAL_BLOCK = 559; - public static final int TUBE_CORAL_FAN = 560; - public static final int TUBE_CORAL_WALL_FAN = 561; - public static final int TURTLE_EGG = 562; - public static final int VINE = 563; - public static final int VOID_AIR = 564; - public static final int WALL_SIGN = 565; + public static final int AIR = 1; + public static final int CAVE_AIR = 2; + public static final int VOID_AIR = 3; + public static final int ACACIA_BUTTON = 4; + public static final int ACACIA_DOOR = 5; + public static final int ACACIA_FENCE = 6; + public static final int ACACIA_FENCE_GATE = 7; + public static final int ACACIA_LEAVES = 8; + public static final int ACACIA_LOG = 9; + public static final int ACACIA_PLANKS = 10; + public static final int ACACIA_PRESSURE_PLATE = 11; + public static final int ACACIA_SAPLING = 12; + public static final int ACACIA_SIGN = 501; + public static final int ACACIA_SLAB = 13; + public static final int ACACIA_STAIRS = 14; + public static final int ACACIA_TRAPDOOR = 15; + public static final int ACACIA_WALL_SIGN = 565; + public static final int ACACIA_WOOD = 16; + public static final int ACTIVATOR_RAIL = 17; + public static final int ALLIUM = 18; + public static final int ANDESITE = 19; + public static final int ANDESITE_SLAB = 599; + public static final int ANDESITE_STAIRS = 600; + public static final int ANDESITE_WALL = 601; + public static final int ANVIL = 20; + public static final int ATTACHED_MELON_STEM = 21; + public static final int ATTACHED_PUMPKIN_STEM = 22; + public static final int AZURE_BLUET = 23; + public static final int BAMBOO = 602; + public static final int BAMBOO_SAPLING = 603; + public static final int BARREL = 604; + public static final int BARRIER = 24; + public static final int BEACON = 25; + public static final int BEDROCK = 26; + public static final int BEETROOTS = 27; + public static final int BELL = 605; + public static final int BIRCH_BUTTON = 28; + public static final int BIRCH_DOOR = 29; + public static final int BIRCH_FENCE = 30; + public static final int BIRCH_FENCE_GATE = 31; + public static final int BIRCH_LEAVES = 32; + public static final int BIRCH_LOG = 33; + public static final int BIRCH_PLANKS = 34; + public static final int BIRCH_PRESSURE_PLATE = 35; + public static final int BIRCH_SAPLING = 36; + public static final int BIRCH_SIGN = 606; + public static final int BIRCH_SLAB = 37; + public static final int BIRCH_STAIRS = 38; + public static final int BIRCH_TRAPDOOR = 39; + public static final int BIRCH_WALL_SIGN = 607; + public static final int BIRCH_WOOD = 40; + public static final int BLACK_BANNER = 41; + public static final int BLACK_BED = 42; + public static final int BLACK_CARPET = 43; + public static final int BLACK_CONCRETE = 44; + public static final int BLACK_CONCRETE_POWDER = 45; + public static final int BLACK_GLAZED_TERRACOTTA = 46; + public static final int BLACK_SHULKER_BOX = 47; + public static final int BLACK_STAINED_GLASS = 48; + public static final int BLACK_STAINED_GLASS_PANE = 49; + public static final int BLACK_TERRACOTTA = 50; + public static final int BLACK_WALL_BANNER = 51; + public static final int BLACK_WOOL = 52; + public static final int BLAST_FURNACE = 608; + public static final int BLUE_BANNER = 53; + public static final int BLUE_BED = 54; + public static final int BLUE_CARPET = 55; + public static final int BLUE_CONCRETE = 56; + public static final int BLUE_CONCRETE_POWDER = 57; + public static final int BLUE_GLAZED_TERRACOTTA = 58; + public static final int BLUE_ICE = 59; + public static final int BLUE_ORCHID = 60; + public static final int BLUE_SHULKER_BOX = 61; + public static final int BLUE_STAINED_GLASS = 62; + public static final int BLUE_STAINED_GLASS_PANE = 63; + public static final int BLUE_TERRACOTTA = 64; + public static final int BLUE_WALL_BANNER = 65; + public static final int BLUE_WOOL = 66; + public static final int BONE_BLOCK = 67; + public static final int BOOKSHELF = 68; + public static final int BRAIN_CORAL = 69; + public static final int BRAIN_CORAL_BLOCK = 70; + public static final int BRAIN_CORAL_FAN = 71; + public static final int BRAIN_CORAL_WALL_FAN = 72; + public static final int BREWING_STAND = 73; + public static final int BRICK_SLAB = 74; + public static final int BRICK_STAIRS = 75; + public static final int BRICK_WALL = 609; + public static final int BRICKS = 76; + public static final int BROWN_BANNER = 77; + public static final int BROWN_BED = 78; + public static final int BROWN_CARPET = 79; + public static final int BROWN_CONCRETE = 80; + public static final int BROWN_CONCRETE_POWDER = 81; + public static final int BROWN_GLAZED_TERRACOTTA = 82; + public static final int BROWN_MUSHROOM = 83; + public static final int BROWN_MUSHROOM_BLOCK = 84; + public static final int BROWN_SHULKER_BOX = 85; + public static final int BROWN_STAINED_GLASS = 86; + public static final int BROWN_STAINED_GLASS_PANE = 87; + public static final int BROWN_TERRACOTTA = 88; + public static final int BROWN_WALL_BANNER = 89; + public static final int BROWN_WOOL = 90; + public static final int BUBBLE_COLUMN = 91; + public static final int BUBBLE_CORAL = 92; + public static final int BUBBLE_CORAL_BLOCK = 93; + public static final int BUBBLE_CORAL_FAN = 94; + public static final int BUBBLE_CORAL_WALL_FAN = 95; + public static final int CACTUS = 96; + public static final int CAKE = 97; + public static final int CAMPFIRE = 610; + public static final int CARROTS = 98; + public static final int CARTOGRAPHY_TABLE = 611; + public static final int CARVED_PUMPKIN = 99; + public static final int CAULDRON = 100; + public static final int CHAIN_COMMAND_BLOCK = 101; + public static final int CHEST = 102; + public static final int CHIPPED_ANVIL = 103; + public static final int CHISELED_QUARTZ_BLOCK = 104; + public static final int CHISELED_RED_SANDSTONE = 105; + public static final int CHISELED_SANDSTONE = 106; + public static final int CHISELED_STONE_BRICKS = 107; + public static final int CHORUS_FLOWER = 108; + public static final int CHORUS_PLANT = 109; + public static final int CLAY = 110; + public static final int COAL_BLOCK = 111; + public static final int COAL_ORE = 112; + public static final int COARSE_DIRT = 113; + public static final int COBBLESTONE = 114; + public static final int COBBLESTONE_SLAB = 115; + public static final int COBBLESTONE_STAIRS = 116; + public static final int COBBLESTONE_WALL = 117; + public static final int COBWEB = 118; + public static final int COCOA = 119; + public static final int COMMAND_BLOCK = 120; + public static final int COMPARATOR = 121; + public static final int COMPOSTER = 612; + public static final int CONDUIT = 122; + public static final int CORNFLOWER = 613; + public static final int CRACKED_STONE_BRICKS = 123; + public static final int CRAFTING_TABLE = 124; + public static final int CREEPER_HEAD = 125; + public static final int CREEPER_WALL_HEAD = 126; + public static final int CUT_RED_SANDSTONE = 127; + public static final int CUT_RED_SANDSTONE_SLAB = 614; + public static final int CUT_SANDSTONE = 128; + public static final int CUT_SANDSTONE_SLAB = 615; + public static final int CYAN_BANNER = 129; + public static final int CYAN_BED = 130; + public static final int CYAN_CARPET = 131; + public static final int CYAN_CONCRETE = 132; + public static final int CYAN_CONCRETE_POWDER = 133; + public static final int CYAN_GLAZED_TERRACOTTA = 134; + public static final int CYAN_SHULKER_BOX = 135; + public static final int CYAN_STAINED_GLASS = 136; + public static final int CYAN_STAINED_GLASS_PANE = 137; + public static final int CYAN_TERRACOTTA = 138; + public static final int CYAN_WALL_BANNER = 139; + public static final int CYAN_WOOL = 140; + public static final int DAMAGED_ANVIL = 141; + public static final int DANDELION = 142; + public static final int DARK_OAK_BUTTON = 143; + public static final int DARK_OAK_DOOR = 144; + public static final int DARK_OAK_FENCE = 145; + public static final int DARK_OAK_FENCE_GATE = 146; + public static final int DARK_OAK_LEAVES = 147; + public static final int DARK_OAK_LOG = 148; + public static final int DARK_OAK_PLANKS = 149; + public static final int DARK_OAK_PRESSURE_PLATE = 150; + public static final int DARK_OAK_SAPLING = 151; + public static final int DARK_OAK_SIGN = 616; + public static final int DARK_OAK_SLAB = 152; + public static final int DARK_OAK_STAIRS = 153; + public static final int DARK_OAK_TRAPDOOR = 154; + public static final int DARK_OAK_WALL_SIGN = 617; + public static final int DARK_OAK_WOOD = 155; + public static final int DARK_PRISMARINE = 156; + public static final int DARK_PRISMARINE_SLAB = 157; + public static final int DARK_PRISMARINE_STAIRS = 158; + public static final int DAYLIGHT_DETECTOR = 159; + public static final int DEAD_BRAIN_CORAL = 160; + public static final int DEAD_BRAIN_CORAL_BLOCK = 161; + public static final int DEAD_BRAIN_CORAL_FAN = 162; + public static final int DEAD_BRAIN_CORAL_WALL_FAN = 163; + public static final int DEAD_BUBBLE_CORAL = 164; + public static final int DEAD_BUBBLE_CORAL_BLOCK = 165; + public static final int DEAD_BUBBLE_CORAL_FAN = 166; + public static final int DEAD_BUBBLE_CORAL_WALL_FAN = 167; + public static final int DEAD_BUSH = 168; + public static final int DEAD_FIRE_CORAL = 169; + public static final int DEAD_FIRE_CORAL_BLOCK = 170; + public static final int DEAD_FIRE_CORAL_FAN = 171; + public static final int DEAD_FIRE_CORAL_WALL_FAN = 172; + public static final int DEAD_HORN_CORAL = 173; + public static final int DEAD_HORN_CORAL_BLOCK = 174; + public static final int DEAD_HORN_CORAL_FAN = 175; + public static final int DEAD_HORN_CORAL_WALL_FAN = 176; + public static final int DEAD_TUBE_CORAL = 177; + public static final int DEAD_TUBE_CORAL_BLOCK = 178; + public static final int DEAD_TUBE_CORAL_FAN = 179; + public static final int DEAD_TUBE_CORAL_WALL_FAN = 180; + public static final int DETECTOR_RAIL = 181; + public static final int DIAMOND_BLOCK = 182; + public static final int DIAMOND_ORE = 183; + public static final int DIORITE = 184; + public static final int DIORITE_SLAB = 618; + public static final int DIORITE_STAIRS = 619; + public static final int DIORITE_WALL = 620; + public static final int DIRT = 185; + public static final int DISPENSER = 186; + public static final int DRAGON_EGG = 187; + public static final int DRAGON_HEAD = 188; + public static final int DRAGON_WALL_HEAD = 189; + public static final int DRIED_KELP_BLOCK = 190; + public static final int DROPPER = 191; + public static final int EMERALD_BLOCK = 192; + public static final int EMERALD_ORE = 193; + public static final int ENCHANTING_TABLE = 194; + public static final int END_GATEWAY = 195; + public static final int END_PORTAL = 196; + public static final int END_PORTAL_FRAME = 197; + public static final int END_ROD = 198; + public static final int END_STONE = 199; + public static final int END_STONE_BRICK_SLAB = 621; + public static final int END_STONE_BRICK_STAIRS = 622; + public static final int END_STONE_BRICK_WALL = 623; + public static final int END_STONE_BRICKS = 200; + public static final int ENDER_CHEST = 201; + public static final int FARMLAND = 202; + public static final int FERN = 203; + public static final int FIRE = 204; + public static final int FIRE_CORAL = 205; + public static final int FIRE_CORAL_BLOCK = 206; + public static final int FIRE_CORAL_FAN = 207; + public static final int FIRE_CORAL_WALL_FAN = 208; + public static final int FLETCHING_TABLE = 624; + public static final int FLOWER_POT = 209; + public static final int FROSTED_ICE = 210; + public static final int FURNACE = 211; + public static final int GLASS = 212; + public static final int GLASS_PANE = 213; + public static final int GLOWSTONE = 214; + public static final int GOLD_BLOCK = 215; + public static final int GOLD_ORE = 216; + public static final int GRANITE = 217; + public static final int GRANITE_SLAB = 625; + public static final int GRANITE_STAIRS = 626; + public static final int GRANITE_WALL = 627; + public static final int GRASS = 218; + public static final int GRASS_BLOCK = 219; + public static final int GRASS_PATH = 220; + public static final int GRAVEL = 221; + public static final int GRAY_BANNER = 222; + public static final int GRAY_BED = 223; + public static final int GRAY_CARPET = 224; + public static final int GRAY_CONCRETE = 225; + public static final int GRAY_CONCRETE_POWDER = 226; + public static final int GRAY_GLAZED_TERRACOTTA = 227; + public static final int GRAY_SHULKER_BOX = 228; + public static final int GRAY_STAINED_GLASS = 229; + public static final int GRAY_STAINED_GLASS_PANE = 230; + public static final int GRAY_TERRACOTTA = 231; + public static final int GRAY_WALL_BANNER = 232; + public static final int GRAY_WOOL = 233; + public static final int GREEN_BANNER = 234; + public static final int GREEN_BED = 235; + public static final int GREEN_CARPET = 236; + public static final int GREEN_CONCRETE = 237; + public static final int GREEN_CONCRETE_POWDER = 238; + public static final int GREEN_GLAZED_TERRACOTTA = 239; + public static final int GREEN_SHULKER_BOX = 240; + public static final int GREEN_STAINED_GLASS = 241; + public static final int GREEN_STAINED_GLASS_PANE = 242; + public static final int GREEN_TERRACOTTA = 243; + public static final int GREEN_WALL_BANNER = 244; + public static final int GREEN_WOOL = 245; + public static final int GRINDSTONE = 628; + public static final int HAY_BLOCK = 246; + public static final int HEAVY_WEIGHTED_PRESSURE_PLATE = 247; + public static final int HOPPER = 248; + public static final int HORN_CORAL = 249; + public static final int HORN_CORAL_BLOCK = 250; + public static final int HORN_CORAL_FAN = 251; + public static final int HORN_CORAL_WALL_FAN = 252; + public static final int ICE = 253; + public static final int INFESTED_CHISELED_STONE_BRICKS = 254; + public static final int INFESTED_COBBLESTONE = 255; + public static final int INFESTED_CRACKED_STONE_BRICKS = 256; + public static final int INFESTED_MOSSY_STONE_BRICKS = 257; + public static final int INFESTED_STONE = 258; + public static final int INFESTED_STONE_BRICKS = 259; + public static final int IRON_BARS = 260; + public static final int IRON_BLOCK = 261; + public static final int IRON_DOOR = 262; + public static final int IRON_ORE = 263; + public static final int IRON_TRAPDOOR = 264; + public static final int JACK_O_LANTERN = 265; + public static final int JIGSAW = 629; + public static final int JUKEBOX = 266; + public static final int JUNGLE_BUTTON = 267; + public static final int JUNGLE_DOOR = 268; + public static final int JUNGLE_FENCE = 269; + public static final int JUNGLE_FENCE_GATE = 270; + public static final int JUNGLE_LEAVES = 271; + public static final int JUNGLE_LOG = 272; + public static final int JUNGLE_PLANKS = 273; + public static final int JUNGLE_PRESSURE_PLATE = 274; + public static final int JUNGLE_SAPLING = 275; + public static final int JUNGLE_SIGN = 630; + public static final int JUNGLE_SLAB = 276; + public static final int JUNGLE_STAIRS = 277; + public static final int JUNGLE_TRAPDOOR = 278; + public static final int JUNGLE_WALL_SIGN = 631; + public static final int JUNGLE_WOOD = 279; + public static final int KELP = 280; + public static final int KELP_PLANT = 281; + public static final int LADDER = 282; + public static final int LANTERN = 632; + public static final int LAPIS_BLOCK = 283; + public static final int LAPIS_ORE = 284; + public static final int LARGE_FERN = 285; + public static final int LAVA = 286; + public static final int LECTERN = 633; + public static final int LEVER = 287; + public static final int LIGHT_BLUE_BANNER = 288; + public static final int LIGHT_BLUE_BED = 289; + public static final int LIGHT_BLUE_CARPET = 290; + public static final int LIGHT_BLUE_CONCRETE = 291; + public static final int LIGHT_BLUE_CONCRETE_POWDER = 292; + public static final int LIGHT_BLUE_GLAZED_TERRACOTTA = 293; + public static final int LIGHT_BLUE_SHULKER_BOX = 294; + public static final int LIGHT_BLUE_STAINED_GLASS = 295; + public static final int LIGHT_BLUE_STAINED_GLASS_PANE = 296; + public static final int LIGHT_BLUE_TERRACOTTA = 297; + public static final int LIGHT_BLUE_WALL_BANNER = 298; + public static final int LIGHT_BLUE_WOOL = 299; + public static final int LIGHT_GRAY_BANNER = 300; + public static final int LIGHT_GRAY_BED = 301; + public static final int LIGHT_GRAY_CARPET = 302; + public static final int LIGHT_GRAY_CONCRETE = 303; + public static final int LIGHT_GRAY_CONCRETE_POWDER = 304; + public static final int LIGHT_GRAY_GLAZED_TERRACOTTA = 305; + public static final int LIGHT_GRAY_SHULKER_BOX = 306; + public static final int LIGHT_GRAY_STAINED_GLASS = 307; + public static final int LIGHT_GRAY_STAINED_GLASS_PANE = 308; + public static final int LIGHT_GRAY_TERRACOTTA = 309; + public static final int LIGHT_GRAY_WALL_BANNER = 310; + public static final int LIGHT_GRAY_WOOL = 311; + public static final int LIGHT_WEIGHTED_PRESSURE_PLATE = 312; + public static final int LILAC = 313; + public static final int LILY_OF_THE_VALLEY = 634; + public static final int LILY_PAD = 314; + public static final int LIME_BANNER = 315; + public static final int LIME_BED = 316; + public static final int LIME_CARPET = 317; + public static final int LIME_CONCRETE = 318; + public static final int LIME_CONCRETE_POWDER = 319; + public static final int LIME_GLAZED_TERRACOTTA = 320; + public static final int LIME_SHULKER_BOX = 321; + public static final int LIME_STAINED_GLASS = 322; + public static final int LIME_STAINED_GLASS_PANE = 323; + public static final int LIME_TERRACOTTA = 324; + public static final int LIME_WALL_BANNER = 325; + public static final int LIME_WOOL = 326; + public static final int LOOM = 635; + public static final int MAGENTA_BANNER = 327; + public static final int MAGENTA_BED = 328; + public static final int MAGENTA_CARPET = 329; + public static final int MAGENTA_CONCRETE = 330; + public static final int MAGENTA_CONCRETE_POWDER = 331; + public static final int MAGENTA_GLAZED_TERRACOTTA = 332; + public static final int MAGENTA_SHULKER_BOX = 333; + public static final int MAGENTA_STAINED_GLASS = 334; + public static final int MAGENTA_STAINED_GLASS_PANE = 335; + public static final int MAGENTA_TERRACOTTA = 336; + public static final int MAGENTA_WALL_BANNER = 337; + public static final int MAGENTA_WOOL = 338; + public static final int MAGMA_BLOCK = 339; + public static final int MELON = 340; + public static final int MELON_STEM = 341; + public static final int MOSSY_COBBLESTONE = 342; + public static final int MOSSY_COBBLESTONE_SLAB = 636; + public static final int MOSSY_COBBLESTONE_STAIRS = 637; + public static final int MOSSY_COBBLESTONE_WALL = 343; + public static final int MOSSY_STONE_BRICK_SLAB = 638; + public static final int MOSSY_STONE_BRICK_STAIRS = 639; + public static final int MOSSY_STONE_BRICK_WALL = 640; + public static final int MOSSY_STONE_BRICKS = 344; + public static final int MOVING_PISTON = 345; + public static final int MUSHROOM_STEM = 346; + public static final int MYCELIUM = 347; + public static final int NETHER_BRICK_FENCE = 348; + public static final int NETHER_BRICK_SLAB = 349; + public static final int NETHER_BRICK_STAIRS = 350; + public static final int NETHER_BRICK_WALL = 641; + public static final int NETHER_BRICKS = 351; + public static final int NETHER_PORTAL = 352; + public static final int NETHER_QUARTZ_ORE = 353; + public static final int NETHER_WART = 354; + public static final int NETHER_WART_BLOCK = 355; + public static final int NETHERRACK = 356; + public static final int NOTE_BLOCK = 357; + public static final int OAK_BUTTON = 358; + public static final int OAK_DOOR = 359; + public static final int OAK_FENCE = 360; + public static final int OAK_FENCE_GATE = 361; + public static final int OAK_LEAVES = 362; + public static final int OAK_LOG = 363; + public static final int OAK_PLANKS = 364; + public static final int OAK_PRESSURE_PLATE = 365; + public static final int OAK_SAPLING = 366; + public static final int OAK_SIGN = 642; + public static final int OAK_SLAB = 367; + public static final int OAK_STAIRS = 368; + public static final int OAK_TRAPDOOR = 369; + public static final int OAK_WALL_SIGN = 643; + public static final int OAK_WOOD = 370; + public static final int OBSERVER = 371; + public static final int OBSIDIAN = 372; + public static final int ORANGE_BANNER = 373; + public static final int ORANGE_BED = 374; + public static final int ORANGE_CARPET = 375; + public static final int ORANGE_CONCRETE = 376; + public static final int ORANGE_CONCRETE_POWDER = 377; + public static final int ORANGE_GLAZED_TERRACOTTA = 378; + public static final int ORANGE_SHULKER_BOX = 379; + public static final int ORANGE_STAINED_GLASS = 380; + public static final int ORANGE_STAINED_GLASS_PANE = 381; + public static final int ORANGE_TERRACOTTA = 382; + public static final int ORANGE_TULIP = 383; + public static final int ORANGE_WALL_BANNER = 384; + public static final int ORANGE_WOOL = 385; + public static final int OXEYE_DAISY = 386; + public static final int PACKED_ICE = 387; + public static final int PEONY = 388; + public static final int PETRIFIED_OAK_SLAB = 389; + public static final int PINK_BANNER = 390; + public static final int PINK_BED = 391; + public static final int PINK_CARPET = 392; + public static final int PINK_CONCRETE = 393; + public static final int PINK_CONCRETE_POWDER = 394; + public static final int PINK_GLAZED_TERRACOTTA = 395; + public static final int PINK_SHULKER_BOX = 396; + public static final int PINK_STAINED_GLASS = 397; + public static final int PINK_STAINED_GLASS_PANE = 398; + public static final int PINK_TERRACOTTA = 399; + public static final int PINK_TULIP = 400; + public static final int PINK_WALL_BANNER = 401; + public static final int PINK_WOOL = 402; + public static final int PISTON = 403; + public static final int PISTON_HEAD = 404; + public static final int PLAYER_HEAD = 405; + public static final int PLAYER_WALL_HEAD = 406; + public static final int PODZOL = 407; + public static final int POLISHED_ANDESITE = 408; + public static final int POLISHED_ANDESITE_SLAB = 644; + public static final int POLISHED_ANDESITE_STAIRS = 645; + public static final int POLISHED_DIORITE = 409; + public static final int POLISHED_DIORITE_SLAB = 646; + public static final int POLISHED_DIORITE_STAIRS = 647; + public static final int POLISHED_GRANITE = 410; + public static final int POLISHED_GRANITE_SLAB = 648; + public static final int POLISHED_GRANITE_STAIRS = 649; + public static final int POPPY = 411; + public static final int POTATOES = 412; + public static final int POTTED_ACACIA_SAPLING = 413; + public static final int POTTED_ALLIUM = 414; + public static final int POTTED_AZURE_BLUET = 415; + public static final int POTTED_BAMBOO = 650; + public static final int POTTED_BIRCH_SAPLING = 416; + public static final int POTTED_BLUE_ORCHID = 417; + public static final int POTTED_BROWN_MUSHROOM = 418; + public static final int POTTED_CACTUS = 419; + public static final int POTTED_CORNFLOWER = 651; + public static final int POTTED_DANDELION = 420; + public static final int POTTED_DARK_OAK_SAPLING = 421; + public static final int POTTED_DEAD_BUSH = 422; + public static final int POTTED_FERN = 423; + public static final int POTTED_JUNGLE_SAPLING = 424; + public static final int POTTED_LILY_OF_THE_VALLEY = 652; + public static final int POTTED_OAK_SAPLING = 425; + public static final int POTTED_ORANGE_TULIP = 426; + public static final int POTTED_OXEYE_DAISY = 427; + public static final int POTTED_PINK_TULIP = 428; + public static final int POTTED_POPPY = 429; + public static final int POTTED_RED_MUSHROOM = 430; + public static final int POTTED_RED_TULIP = 431; + public static final int POTTED_SPRUCE_SAPLING = 432; + public static final int POTTED_WHITE_TULIP = 433; + public static final int POTTED_WITHER_ROSE = 653; + public static final int POWERED_RAIL = 434; + public static final int PRISMARINE = 435; + public static final int PRISMARINE_BRICK_SLAB = 436; + public static final int PRISMARINE_BRICK_STAIRS = 437; + public static final int PRISMARINE_BRICKS = 438; + public static final int PRISMARINE_SLAB = 439; + public static final int PRISMARINE_STAIRS = 440; + public static final int PRISMARINE_WALL = 654; + public static final int PUMPKIN = 441; + public static final int PUMPKIN_STEM = 442; + public static final int PURPLE_BANNER = 443; + public static final int PURPLE_BED = 444; + public static final int PURPLE_CARPET = 445; + public static final int PURPLE_CONCRETE = 446; + public static final int PURPLE_CONCRETE_POWDER = 447; + public static final int PURPLE_GLAZED_TERRACOTTA = 448; + public static final int PURPLE_SHULKER_BOX = 449; + public static final int PURPLE_STAINED_GLASS = 450; + public static final int PURPLE_STAINED_GLASS_PANE = 451; + public static final int PURPLE_TERRACOTTA = 452; + public static final int PURPLE_WALL_BANNER = 453; + public static final int PURPLE_WOOL = 454; + public static final int PURPUR_BLOCK = 455; + public static final int PURPUR_PILLAR = 456; + public static final int PURPUR_SLAB = 457; + public static final int PURPUR_STAIRS = 458; + public static final int QUARTZ_BLOCK = 459; + public static final int QUARTZ_PILLAR = 460; + public static final int QUARTZ_SLAB = 461; + public static final int QUARTZ_STAIRS = 462; + public static final int RAIL = 463; + public static final int RED_BANNER = 464; + public static final int RED_BED = 465; + public static final int RED_CARPET = 466; + public static final int RED_CONCRETE = 467; + public static final int RED_CONCRETE_POWDER = 468; + public static final int RED_GLAZED_TERRACOTTA = 469; + public static final int RED_MUSHROOM = 470; + public static final int RED_MUSHROOM_BLOCK = 471; + public static final int RED_NETHER_BRICK_SLAB = 655; + public static final int RED_NETHER_BRICK_STAIRS = 656; + public static final int RED_NETHER_BRICK_WALL = 657; + public static final int RED_NETHER_BRICKS = 472; + public static final int RED_SAND = 473; + public static final int RED_SANDSTONE = 474; + public static final int RED_SANDSTONE_SLAB = 475; + public static final int RED_SANDSTONE_STAIRS = 476; + public static final int RED_SANDSTONE_WALL = 658; + public static final int RED_SHULKER_BOX = 477; + public static final int RED_STAINED_GLASS = 478; + public static final int RED_STAINED_GLASS_PANE = 479; + public static final int RED_TERRACOTTA = 480; + public static final int RED_TULIP = 481; + public static final int RED_WALL_BANNER = 482; + public static final int RED_WOOL = 483; + public static final int REDSTONE_BLOCK = 484; + public static final int REDSTONE_LAMP = 485; + public static final int REDSTONE_ORE = 486; + public static final int REDSTONE_TORCH = 487; + public static final int REDSTONE_WALL_TORCH = 488; + public static final int REDSTONE_WIRE = 489; + public static final int REPEATER = 490; + public static final int REPEATING_COMMAND_BLOCK = 491; + public static final int ROSE_BUSH = 492; + public static final int SAND = 493; + public static final int SANDSTONE = 494; + public static final int SANDSTONE_SLAB = 495; + public static final int SANDSTONE_STAIRS = 496; + public static final int SANDSTONE_WALL = 659; + public static final int SCAFFOLDING = 660; + public static final int SEA_LANTERN = 497; + public static final int SEA_PICKLE = 498; + public static final int SEAGRASS = 499; + public static final int SHULKER_BOX = 500; + public static final int SKELETON_SKULL = 502; + public static final int SKELETON_WALL_SKULL = 503; + public static final int SLIME_BLOCK = 504; + public static final int SMITHING_TABLE = 661; + public static final int SMOKER = 662; + public static final int SMOOTH_QUARTZ = 505; + public static final int SMOOTH_QUARTZ_SLAB = 663; + public static final int SMOOTH_QUARTZ_STAIRS = 664; + public static final int SMOOTH_RED_SANDSTONE = 506; + public static final int SMOOTH_RED_SANDSTONE_SLAB = 665; + public static final int SMOOTH_RED_SANDSTONE_STAIRS = 666; + public static final int SMOOTH_SANDSTONE = 507; + public static final int SMOOTH_SANDSTONE_SLAB = 667; + public static final int SMOOTH_SANDSTONE_STAIRS = 668; + public static final int SMOOTH_STONE = 508; + public static final int SMOOTH_STONE_SLAB = 669; + public static final int SNOW = 509; + public static final int SNOW_BLOCK = 510; + public static final int SOUL_SAND = 511; + public static final int SPAWNER = 512; + public static final int SPONGE = 513; + public static final int SPRUCE_BUTTON = 514; + public static final int SPRUCE_DOOR = 515; + public static final int SPRUCE_FENCE = 516; + public static final int SPRUCE_FENCE_GATE = 517; + public static final int SPRUCE_LEAVES = 518; + public static final int SPRUCE_LOG = 519; + public static final int SPRUCE_PLANKS = 520; + public static final int SPRUCE_PRESSURE_PLATE = 521; + public static final int SPRUCE_SAPLING = 522; + public static final int SPRUCE_SIGN = 670; + public static final int SPRUCE_SLAB = 523; + public static final int SPRUCE_STAIRS = 524; + public static final int SPRUCE_TRAPDOOR = 525; + public static final int SPRUCE_WALL_SIGN = 671; + public static final int SPRUCE_WOOD = 526; + public static final int STICKY_PISTON = 527; + public static final int STONE = 528; + public static final int STONE_BRICK_SLAB = 529; + public static final int STONE_BRICK_STAIRS = 530; + public static final int STONE_BRICK_WALL = 672; + public static final int STONE_BRICKS = 531; + public static final int STONE_BUTTON = 532; + public static final int STONE_PRESSURE_PLATE = 533; + public static final int STONE_SLAB = 534; + public static final int STONE_STAIRS = 673; + public static final int STONECUTTER = 674; + public static final int STRIPPED_ACACIA_LOG = 535; + public static final int STRIPPED_ACACIA_WOOD = 536; + public static final int STRIPPED_BIRCH_LOG = 537; + public static final int STRIPPED_BIRCH_WOOD = 538; + public static final int STRIPPED_DARK_OAK_LOG = 539; + public static final int STRIPPED_DARK_OAK_WOOD = 540; + public static final int STRIPPED_JUNGLE_LOG = 541; + public static final int STRIPPED_JUNGLE_WOOD = 542; + public static final int STRIPPED_OAK_LOG = 543; + public static final int STRIPPED_OAK_WOOD = 544; + public static final int STRIPPED_SPRUCE_LOG = 545; + public static final int STRIPPED_SPRUCE_WOOD = 546; + public static final int STRUCTURE_BLOCK = 547; + public static final int STRUCTURE_VOID = 548; + public static final int SUGAR_CANE = 549; + public static final int SUNFLOWER = 550; + public static final int SWEET_BERRY_BUSH = 675; + public static final int TALL_GRASS = 551; + public static final int TALL_SEAGRASS = 552; + public static final int TERRACOTTA = 553; + public static final int TNT = 554; + public static final int TORCH = 555; + public static final int TRAPPED_CHEST = 556; + public static final int TRIPWIRE = 557; + public static final int TRIPWIRE_HOOK = 558; + public static final int TUBE_CORAL = 559; + public static final int TUBE_CORAL_BLOCK = 560; + public static final int TUBE_CORAL_FAN = 561; + public static final int TUBE_CORAL_WALL_FAN = 562; + public static final int TURTLE_EGG = 563; + public static final int VINE = 564; public static final int WALL_TORCH = 566; public static final int WATER = 567; public static final int WET_SPONGE = 568; @@ -585,6 +662,7 @@ public class BlockID { public static final int WHITE_TULIP = 580; public static final int WHITE_WALL_BANNER = 581; public static final int WHITE_WOOL = 582; + public static final int WITHER_ROSE = 676; public static final int WITHER_SKELETON_SKULL = 583; public static final int WITHER_SKELETON_WALL_SKULL = 584; public static final int YELLOW_BANNER = 585; @@ -601,4 +679,8 @@ public class BlockID { public static final int YELLOW_WOOL = 596; public static final int ZOMBIE_HEAD = 597; public static final int ZOMBIE_WALL_HEAD = 598; + + // Deprecated + public static final int SIGN = OAK_SIGN; + public static final int WALL_SIGN = OAK_WALL_SIGN; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index ad81aeaad..05a66f136 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.world.block; +import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.command.SuggestInputParseException; import com.boydti.fawe.object.string.MutableCharSequence; import com.boydti.fawe.util.StringMan; @@ -49,6 +50,7 @@ import java.util.stream.Stream; public class BlockState implements BlockStateHolder, FawePattern { private final int internalId; private final int ordinal; + private final char ordinalChar; private final BlockType blockType; private BlockMaterial material; private BaseBlock emptyBaseBlock; @@ -57,7 +59,8 @@ public class BlockState implements BlockStateHolder, FawePattern { this.blockType = blockType; this.internalId = internalId; this.ordinal = ordinal; - this.emptyBaseBlock = new BaseBlock(this); + this.ordinalChar = (char) ordinal; + this.emptyBaseBlock = new ImmutableBaseBlock(this); } /** @@ -214,7 +217,7 @@ public class BlockState implements BlockStateHolder, FawePattern { } @Override public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - return extent.setBlock(set, this); + return set.setBlock(extent, this); } @Override @@ -270,6 +273,24 @@ public class BlockState implements BlockStateHolder, FawePattern { } } + public BlockState withProperties(final BlockState other) { + BlockType ot = other.getBlockType(); + if (ot == blockType) { + return other; + } + if (ot.getProperties().isEmpty() || blockType.getProperties().isEmpty()) { + return this; + } + BlockState newState = this; + for (Property prop: ot.getProperties()) { + PropertyKey key = prop.getKey(); + if (blockType.hasProperty(key)) { + newState = newState.with(key, other.getState(key)); + } + } + return this; + } + @Override public Map, Object> getStates() { BlockType type = this.getBlockType(); @@ -333,10 +354,15 @@ public class BlockState implements BlockStateHolder, FawePattern { return material; } - @Override - public int getOrdinal() { - return this.ordinal; - } + @Override + public final int getOrdinal() { + return this.ordinal; + } + + @Override + public final char getOrdinalChar() { + return this.ordinalChar; + } @Override public String toString() { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java index eed1c68eb..5b8e12032 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java @@ -64,6 +64,9 @@ public interface BlockStateHolder> extends FawePat @Deprecated int getOrdinal(); + @Deprecated + char getOrdinalChar(); + BlockMaterial getMaterial(); /** * Get type id (legacy uses) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java index dcf1baba6..2abc4d052 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java @@ -41,7 +41,9 @@ import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; +import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -61,22 +63,31 @@ public final class BlockTypes { @Nullable public static final BlockType ACACIA_PLANKS = null; @Nullable public static final BlockType ACACIA_PRESSURE_PLATE = null; @Nullable public static final BlockType ACACIA_SAPLING = null; + @Nullable public static final BlockType ACACIA_SIGN = null; @Nullable public static final BlockType ACACIA_SLAB = null; @Nullable public static final BlockType ACACIA_STAIRS = null; @Nullable public static final BlockType ACACIA_TRAPDOOR = null; + @Nullable public static final BlockType ACACIA_WALL_SIGN = null; @Nullable public static final BlockType ACACIA_WOOD = null; @Nullable public static final BlockType ACTIVATOR_RAIL = null; @Nullable public static final BlockType AIR = null; @Nullable public static final BlockType ALLIUM = null; @Nullable public static final BlockType ANDESITE = null; + @Nullable public static final BlockType ANDESITE_SLAB = null; + @Nullable public static final BlockType ANDESITE_STAIRS = null; + @Nullable public static final BlockType ANDESITE_WALL = null; @Nullable public static final BlockType ANVIL = null; @Nullable public static final BlockType ATTACHED_MELON_STEM = null; @Nullable public static final BlockType ATTACHED_PUMPKIN_STEM = null; @Nullable public static final BlockType AZURE_BLUET = null; + @Nullable public static final BlockType BAMBOO = null; + @Nullable public static final BlockType BAMBOO_SAPLING = null; + @Nullable public static final BlockType BARREL = null; @Nullable public static final BlockType BARRIER = null; @Nullable public static final BlockType BEACON = null; @Nullable public static final BlockType BEDROCK = null; @Nullable public static final BlockType BEETROOTS = null; + @Nullable public static final BlockType BELL = null; @Nullable public static final BlockType BIRCH_BUTTON = null; @Nullable public static final BlockType BIRCH_DOOR = null; @Nullable public static final BlockType BIRCH_FENCE = null; @@ -86,9 +97,11 @@ public final class BlockTypes { @Nullable public static final BlockType BIRCH_PLANKS = null; @Nullable public static final BlockType BIRCH_PRESSURE_PLATE = null; @Nullable public static final BlockType BIRCH_SAPLING = null; + @Nullable public static final BlockType BIRCH_SIGN = null; @Nullable public static final BlockType BIRCH_SLAB = null; @Nullable public static final BlockType BIRCH_STAIRS = null; @Nullable public static final BlockType BIRCH_TRAPDOOR = null; + @Nullable public static final BlockType BIRCH_WALL_SIGN = null; @Nullable public static final BlockType BIRCH_WOOD = null; @Nullable public static final BlockType BLACK_BANNER = null; @Nullable public static final BlockType BLACK_BED = null; @@ -102,6 +115,7 @@ public final class BlockTypes { @Nullable public static final BlockType BLACK_TERRACOTTA = null; @Nullable public static final BlockType BLACK_WALL_BANNER = null; @Nullable public static final BlockType BLACK_WOOL = null; + @Nullable public static final BlockType BLAST_FURNACE = null; @Nullable public static final BlockType BLUE_BANNER = null; @Nullable public static final BlockType BLUE_BED = null; @Nullable public static final BlockType BLUE_CARPET = null; @@ -125,6 +139,7 @@ public final class BlockTypes { @Nullable public static final BlockType BREWING_STAND = null; @Nullable public static final BlockType BRICK_SLAB = null; @Nullable public static final BlockType BRICK_STAIRS = null; + @Nullable public static final BlockType BRICK_WALL = null; @Nullable public static final BlockType BRICKS = null; @Nullable public static final BlockType BROWN_BANNER = null; @Nullable public static final BlockType BROWN_BED = null; @@ -147,7 +162,9 @@ public final class BlockTypes { @Nullable public static final BlockType BUBBLE_CORAL_WALL_FAN = null; @Nullable public static final BlockType CACTUS = null; @Nullable public static final BlockType CAKE = null; + @Nullable public static final BlockType CAMPFIRE = null; @Nullable public static final BlockType CARROTS = null; + @Nullable public static final BlockType CARTOGRAPHY_TABLE = null; @Nullable public static final BlockType CARVED_PUMPKIN = null; @Nullable public static final BlockType CAULDRON = null; @Nullable public static final BlockType CAVE_AIR = null; @@ -172,13 +189,17 @@ public final class BlockTypes { @Nullable public static final BlockType COCOA = null; @Nullable public static final BlockType COMMAND_BLOCK = null; @Nullable public static final BlockType COMPARATOR = null; + @Nullable public static final BlockType COMPOSTER = null; @Nullable public static final BlockType CONDUIT = null; + @Nullable public static final BlockType CORNFLOWER = null; @Nullable public static final BlockType CRACKED_STONE_BRICKS = null; @Nullable public static final BlockType CRAFTING_TABLE = null; @Nullable public static final BlockType CREEPER_HEAD = null; @Nullable public static final BlockType CREEPER_WALL_HEAD = null; @Nullable public static final BlockType CUT_RED_SANDSTONE = null; + @Nullable public static final BlockType CUT_RED_SANDSTONE_SLAB = null; @Nullable public static final BlockType CUT_SANDSTONE = null; + @Nullable public static final BlockType CUT_SANDSTONE_SLAB = null; @Nullable public static final BlockType CYAN_BANNER = null; @Nullable public static final BlockType CYAN_BED = null; @Nullable public static final BlockType CYAN_CARPET = null; @@ -202,9 +223,11 @@ public final class BlockTypes { @Nullable public static final BlockType DARK_OAK_PLANKS = null; @Nullable public static final BlockType DARK_OAK_PRESSURE_PLATE = null; @Nullable public static final BlockType DARK_OAK_SAPLING = null; + @Nullable public static final BlockType DARK_OAK_SIGN = null; @Nullable public static final BlockType DARK_OAK_SLAB = null; @Nullable public static final BlockType DARK_OAK_STAIRS = null; @Nullable public static final BlockType DARK_OAK_TRAPDOOR = null; + @Nullable public static final BlockType DARK_OAK_WALL_SIGN = null; @Nullable public static final BlockType DARK_OAK_WOOD = null; @Nullable public static final BlockType DARK_PRISMARINE = null; @Nullable public static final BlockType DARK_PRISMARINE_SLAB = null; @@ -235,6 +258,9 @@ public final class BlockTypes { @Nullable public static final BlockType DIAMOND_BLOCK = null; @Nullable public static final BlockType DIAMOND_ORE = null; @Nullable public static final BlockType DIORITE = null; + @Nullable public static final BlockType DIORITE_SLAB = null; + @Nullable public static final BlockType DIORITE_STAIRS = null; + @Nullable public static final BlockType DIORITE_WALL = null; @Nullable public static final BlockType DIRT = null; @Nullable public static final BlockType DISPENSER = null; @Nullable public static final BlockType DRAGON_EGG = null; @@ -250,6 +276,9 @@ public final class BlockTypes { @Nullable public static final BlockType END_PORTAL_FRAME = null; @Nullable public static final BlockType END_ROD = null; @Nullable public static final BlockType END_STONE = null; + @Nullable public static final BlockType END_STONE_BRICK_SLAB = null; + @Nullable public static final BlockType END_STONE_BRICK_STAIRS = null; + @Nullable public static final BlockType END_STONE_BRICK_WALL = null; @Nullable public static final BlockType END_STONE_BRICKS = null; @Nullable public static final BlockType ENDER_CHEST = null; @Nullable public static final BlockType FARMLAND = null; @@ -259,6 +288,7 @@ public final class BlockTypes { @Nullable public static final BlockType FIRE_CORAL_BLOCK = null; @Nullable public static final BlockType FIRE_CORAL_FAN = null; @Nullable public static final BlockType FIRE_CORAL_WALL_FAN = null; + @Nullable public static final BlockType FLETCHING_TABLE = null; @Nullable public static final BlockType FLOWER_POT = null; @Nullable public static final BlockType FROSTED_ICE = null; @Nullable public static final BlockType FURNACE = null; @@ -268,6 +298,9 @@ public final class BlockTypes { @Nullable public static final BlockType GOLD_BLOCK = null; @Nullable public static final BlockType GOLD_ORE = null; @Nullable public static final BlockType GRANITE = null; + @Nullable public static final BlockType GRANITE_SLAB = null; + @Nullable public static final BlockType GRANITE_STAIRS = null; + @Nullable public static final BlockType GRANITE_WALL = null; @Nullable public static final BlockType GRASS = null; @Nullable public static final BlockType GRASS_BLOCK = null; @Nullable public static final BlockType GRASS_PATH = null; @@ -296,6 +329,7 @@ public final class BlockTypes { @Nullable public static final BlockType GREEN_TERRACOTTA = null; @Nullable public static final BlockType GREEN_WALL_BANNER = null; @Nullable public static final BlockType GREEN_WOOL = null; + @Nullable public static final BlockType GRINDSTONE = null; @Nullable public static final BlockType HAY_BLOCK = null; @Nullable public static final BlockType HEAVY_WEIGHTED_PRESSURE_PLATE = null; @Nullable public static final BlockType HOPPER = null; @@ -316,6 +350,7 @@ public final class BlockTypes { @Nullable public static final BlockType IRON_ORE = null; @Nullable public static final BlockType IRON_TRAPDOOR = null; @Nullable public static final BlockType JACK_O_LANTERN = null; + @Nullable public static final BlockType JIGSAW = null; @Nullable public static final BlockType JUKEBOX = null; @Nullable public static final BlockType JUNGLE_BUTTON = null; @Nullable public static final BlockType JUNGLE_DOOR = null; @@ -326,17 +361,21 @@ public final class BlockTypes { @Nullable public static final BlockType JUNGLE_PLANKS = null; @Nullable public static final BlockType JUNGLE_PRESSURE_PLATE = null; @Nullable public static final BlockType JUNGLE_SAPLING = null; + @Nullable public static final BlockType JUNGLE_SIGN = null; @Nullable public static final BlockType JUNGLE_SLAB = null; @Nullable public static final BlockType JUNGLE_STAIRS = null; @Nullable public static final BlockType JUNGLE_TRAPDOOR = null; + @Nullable public static final BlockType JUNGLE_WALL_SIGN = null; @Nullable public static final BlockType JUNGLE_WOOD = null; @Nullable public static final BlockType KELP = null; @Nullable public static final BlockType KELP_PLANT = null; @Nullable public static final BlockType LADDER = null; + @Nullable public static final BlockType LANTERN = null; @Nullable public static final BlockType LAPIS_BLOCK = null; @Nullable public static final BlockType LAPIS_ORE = null; @Nullable public static final BlockType LARGE_FERN = null; @Nullable public static final BlockType LAVA = null; + @Nullable public static final BlockType LECTERN = null; @Nullable public static final BlockType LEVER = null; @Nullable public static final BlockType LIGHT_BLUE_BANNER = null; @Nullable public static final BlockType LIGHT_BLUE_BED = null; @@ -364,6 +403,7 @@ public final class BlockTypes { @Nullable public static final BlockType LIGHT_GRAY_WOOL = null; @Nullable public static final BlockType LIGHT_WEIGHTED_PRESSURE_PLATE = null; @Nullable public static final BlockType LILAC = null; + @Nullable public static final BlockType LILY_OF_THE_VALLEY = null; @Nullable public static final BlockType LILY_PAD = null; @Nullable public static final BlockType LIME_BANNER = null; @Nullable public static final BlockType LIME_BED = null; @@ -377,6 +417,7 @@ public final class BlockTypes { @Nullable public static final BlockType LIME_TERRACOTTA = null; @Nullable public static final BlockType LIME_WALL_BANNER = null; @Nullable public static final BlockType LIME_WOOL = null; + @Nullable public static final BlockType LOOM = null; @Nullable public static final BlockType MAGENTA_BANNER = null; @Nullable public static final BlockType MAGENTA_BED = null; @Nullable public static final BlockType MAGENTA_CARPET = null; @@ -393,7 +434,12 @@ public final class BlockTypes { @Nullable public static final BlockType MELON = null; @Nullable public static final BlockType MELON_STEM = null; @Nullable public static final BlockType MOSSY_COBBLESTONE = null; + @Nullable public static final BlockType MOSSY_COBBLESTONE_SLAB = null; + @Nullable public static final BlockType MOSSY_COBBLESTONE_STAIRS = null; @Nullable public static final BlockType MOSSY_COBBLESTONE_WALL = null; + @Nullable public static final BlockType MOSSY_STONE_BRICK_SLAB = null; + @Nullable public static final BlockType MOSSY_STONE_BRICK_STAIRS = null; + @Nullable public static final BlockType MOSSY_STONE_BRICK_WALL = null; @Nullable public static final BlockType MOSSY_STONE_BRICKS = null; @Nullable public static final BlockType MOVING_PISTON = null; @Nullable public static final BlockType MUSHROOM_STEM = null; @@ -401,6 +447,7 @@ public final class BlockTypes { @Nullable public static final BlockType NETHER_BRICK_FENCE = null; @Nullable public static final BlockType NETHER_BRICK_SLAB = null; @Nullable public static final BlockType NETHER_BRICK_STAIRS = null; + @Nullable public static final BlockType NETHER_BRICK_WALL = null; @Nullable public static final BlockType NETHER_BRICKS = null; @Nullable public static final BlockType NETHER_PORTAL = null; @Nullable public static final BlockType NETHER_QUARTZ_ORE = null; @@ -417,9 +464,11 @@ public final class BlockTypes { @Nullable public static final BlockType OAK_PLANKS = null; @Nullable public static final BlockType OAK_PRESSURE_PLATE = null; @Nullable public static final BlockType OAK_SAPLING = null; + @Nullable public static final BlockType OAK_SIGN = null; @Nullable public static final BlockType OAK_SLAB = null; @Nullable public static final BlockType OAK_STAIRS = null; @Nullable public static final BlockType OAK_TRAPDOOR = null; + @Nullable public static final BlockType OAK_WALL_SIGN = null; @Nullable public static final BlockType OAK_WOOD = null; @Nullable public static final BlockType OBSERVER = null; @Nullable public static final BlockType OBSIDIAN = null; @@ -459,22 +508,31 @@ public final class BlockTypes { @Nullable public static final BlockType PLAYER_WALL_HEAD = null; @Nullable public static final BlockType PODZOL = null; @Nullable public static final BlockType POLISHED_ANDESITE = null; + @Nullable public static final BlockType POLISHED_ANDESITE_SLAB = null; + @Nullable public static final BlockType POLISHED_ANDESITE_STAIRS = null; @Nullable public static final BlockType POLISHED_DIORITE = null; + @Nullable public static final BlockType POLISHED_DIORITE_SLAB = null; + @Nullable public static final BlockType POLISHED_DIORITE_STAIRS = null; @Nullable public static final BlockType POLISHED_GRANITE = null; + @Nullable public static final BlockType POLISHED_GRANITE_SLAB = null; + @Nullable public static final BlockType POLISHED_GRANITE_STAIRS = null; @Nullable public static final BlockType POPPY = null; @Nullable public static final BlockType POTATOES = null; @Nullable public static final BlockType POTTED_ACACIA_SAPLING = null; @Nullable public static final BlockType POTTED_ALLIUM = null; @Nullable public static final BlockType POTTED_AZURE_BLUET = null; + @Nullable public static final BlockType POTTED_BAMBOO = null; @Nullable public static final BlockType POTTED_BIRCH_SAPLING = null; @Nullable public static final BlockType POTTED_BLUE_ORCHID = null; @Nullable public static final BlockType POTTED_BROWN_MUSHROOM = null; @Nullable public static final BlockType POTTED_CACTUS = null; + @Nullable public static final BlockType POTTED_CORNFLOWER = null; @Nullable public static final BlockType POTTED_DANDELION = null; @Nullable public static final BlockType POTTED_DARK_OAK_SAPLING = null; @Nullable public static final BlockType POTTED_DEAD_BUSH = null; @Nullable public static final BlockType POTTED_FERN = null; @Nullable public static final BlockType POTTED_JUNGLE_SAPLING = null; + @Nullable public static final BlockType POTTED_LILY_OF_THE_VALLEY = null; @Nullable public static final BlockType POTTED_OAK_SAPLING = null; @Nullable public static final BlockType POTTED_ORANGE_TULIP = null; @Nullable public static final BlockType POTTED_OXEYE_DAISY = null; @@ -484,6 +542,7 @@ public final class BlockTypes { @Nullable public static final BlockType POTTED_RED_TULIP = null; @Nullable public static final BlockType POTTED_SPRUCE_SAPLING = null; @Nullable public static final BlockType POTTED_WHITE_TULIP = null; + @Nullable public static final BlockType POTTED_WITHER_ROSE = null; @Nullable public static final BlockType POWERED_RAIL = null; @Nullable public static final BlockType PRISMARINE = null; @Nullable public static final BlockType PRISMARINE_BRICK_SLAB = null; @@ -491,6 +550,7 @@ public final class BlockTypes { @Nullable public static final BlockType PRISMARINE_BRICKS = null; @Nullable public static final BlockType PRISMARINE_SLAB = null; @Nullable public static final BlockType PRISMARINE_STAIRS = null; + @Nullable public static final BlockType PRISMARINE_WALL = null; @Nullable public static final BlockType PUMPKIN = null; @Nullable public static final BlockType PUMPKIN_STEM = null; @Nullable public static final BlockType PURPLE_BANNER = null; @@ -522,11 +582,15 @@ public final class BlockTypes { @Nullable public static final BlockType RED_GLAZED_TERRACOTTA = null; @Nullable public static final BlockType RED_MUSHROOM = null; @Nullable public static final BlockType RED_MUSHROOM_BLOCK = null; + @Nullable public static final BlockType RED_NETHER_BRICK_SLAB = null; + @Nullable public static final BlockType RED_NETHER_BRICK_STAIRS = null; + @Nullable public static final BlockType RED_NETHER_BRICK_WALL = null; @Nullable public static final BlockType RED_NETHER_BRICKS = null; @Nullable public static final BlockType RED_SAND = null; @Nullable public static final BlockType RED_SANDSTONE = null; @Nullable public static final BlockType RED_SANDSTONE_SLAB = null; @Nullable public static final BlockType RED_SANDSTONE_STAIRS = null; + @Nullable public static final BlockType RED_SANDSTONE_WALL = null; @Nullable public static final BlockType RED_SHULKER_BOX = null; @Nullable public static final BlockType RED_STAINED_GLASS = null; @Nullable public static final BlockType RED_STAINED_GLASS_PANE = null; @@ -547,18 +611,28 @@ public final class BlockTypes { @Nullable public static final BlockType SANDSTONE = null; @Nullable public static final BlockType SANDSTONE_SLAB = null; @Nullable public static final BlockType SANDSTONE_STAIRS = null; + @Nullable public static final BlockType SANDSTONE_WALL = null; + @Nullable public static final BlockType SCAFFOLDING = null; @Nullable public static final BlockType SEA_LANTERN = null; @Nullable public static final BlockType SEA_PICKLE = null; @Nullable public static final BlockType SEAGRASS = null; @Nullable public static final BlockType SHULKER_BOX = null; - @Nullable public static final BlockType SIGN = null; @Nullable public static final BlockType SKELETON_SKULL = null; @Nullable public static final BlockType SKELETON_WALL_SKULL = null; @Nullable public static final BlockType SLIME_BLOCK = null; + @Nullable public static final BlockType SMITHING_TABLE = null; + @Nullable public static final BlockType SMOKER = null; @Nullable public static final BlockType SMOOTH_QUARTZ = null; + @Nullable public static final BlockType SMOOTH_QUARTZ_SLAB = null; + @Nullable public static final BlockType SMOOTH_QUARTZ_STAIRS = null; @Nullable public static final BlockType SMOOTH_RED_SANDSTONE = null; + @Nullable public static final BlockType SMOOTH_RED_SANDSTONE_SLAB = null; + @Nullable public static final BlockType SMOOTH_RED_SANDSTONE_STAIRS = null; @Nullable public static final BlockType SMOOTH_SANDSTONE = null; + @Nullable public static final BlockType SMOOTH_SANDSTONE_SLAB = null; + @Nullable public static final BlockType SMOOTH_SANDSTONE_STAIRS = null; @Nullable public static final BlockType SMOOTH_STONE = null; + @Nullable public static final BlockType SMOOTH_STONE_SLAB = null; @Nullable public static final BlockType SNOW = null; @Nullable public static final BlockType SNOW_BLOCK = null; @Nullable public static final BlockType SOUL_SAND = null; @@ -573,18 +647,23 @@ public final class BlockTypes { @Nullable public static final BlockType SPRUCE_PLANKS = null; @Nullable public static final BlockType SPRUCE_PRESSURE_PLATE = null; @Nullable public static final BlockType SPRUCE_SAPLING = null; + @Nullable public static final BlockType SPRUCE_SIGN = null; @Nullable public static final BlockType SPRUCE_SLAB = null; @Nullable public static final BlockType SPRUCE_STAIRS = null; @Nullable public static final BlockType SPRUCE_TRAPDOOR = null; + @Nullable public static final BlockType SPRUCE_WALL_SIGN = null; @Nullable public static final BlockType SPRUCE_WOOD = null; @Nullable public static final BlockType STICKY_PISTON = null; @Nullable public static final BlockType STONE = null; @Nullable public static final BlockType STONE_BRICK_SLAB = null; @Nullable public static final BlockType STONE_BRICK_STAIRS = null; + @Nullable public static final BlockType STONE_BRICK_WALL = null; @Nullable public static final BlockType STONE_BRICKS = null; @Nullable public static final BlockType STONE_BUTTON = null; @Nullable public static final BlockType STONE_PRESSURE_PLATE = null; @Nullable public static final BlockType STONE_SLAB = null; + @Nullable public static final BlockType STONE_STAIRS = null; + @Nullable public static final BlockType STONECUTTER = null; @Nullable public static final BlockType STRIPPED_ACACIA_LOG = null; @Nullable public static final BlockType STRIPPED_ACACIA_WOOD = null; @Nullable public static final BlockType STRIPPED_BIRCH_LOG = null; @@ -601,6 +680,7 @@ public final class BlockTypes { @Nullable public static final BlockType STRUCTURE_VOID = null; @Nullable public static final BlockType SUGAR_CANE = null; @Nullable public static final BlockType SUNFLOWER = null; + @Nullable public static final BlockType SWEET_BERRY_BUSH = null; @Nullable public static final BlockType TALL_GRASS = null; @Nullable public static final BlockType TALL_SEAGRASS = null; @Nullable public static final BlockType TERRACOTTA = null; @@ -616,7 +696,6 @@ public final class BlockTypes { @Nullable public static final BlockType TURTLE_EGG = null; @Nullable public static final BlockType VINE = null; @Nullable public static final BlockType VOID_AIR = null; - @Nullable public static final BlockType WALL_SIGN = null; @Nullable public static final BlockType WALL_TORCH = null; @Nullable public static final BlockType WATER = null; @Nullable public static final BlockType WET_SPONGE = null; @@ -634,6 +713,7 @@ public final class BlockTypes { @Nullable public static final BlockType WHITE_TULIP = null; @Nullable public static final BlockType WHITE_WALL_BANNER = null; @Nullable public static final BlockType WHITE_WOOL = null; + @Nullable public static final BlockType WITHER_ROSE = null; @Nullable public static final BlockType WITHER_SKELETON_SKULL = null; @Nullable public static final BlockType WITHER_SKELETON_WALL_SKULL = null; @Nullable public static final BlockType YELLOW_BANNER = null; @@ -651,6 +731,10 @@ public final class BlockTypes { @Nullable public static final BlockType ZOMBIE_HEAD = null; @Nullable public static final BlockType ZOMBIE_WALL_HEAD = null; + // deprecated + @Deprecated @Nullable public static BlockType SIGN; + @Deprecated @Nullable public static BlockType WALL_SIGN; + /* ----------------------------------------------------- Settings @@ -812,7 +896,7 @@ public final class BlockTypes { for (Field field : oldFields) { if (field.getType() == int.class) { int internalId = field.getInt(null); - String id = "minecraft:" + field.getName().toLowerCase(); + String id = "minecraft:" + field.getName().toLowerCase(Locale.ROOT); String defaultState = blockMap.remove(id); if (defaultState == null) { if (internalId != 0) { @@ -844,10 +928,14 @@ public final class BlockTypes { // Add to $Registry for (BlockType type : values) { - $REGISTRY.put(type.getId().toLowerCase(), type); + $REGISTRY.put(type.getId().toLowerCase(Locale.ROOT), type); } states = stateList.toArray(new BlockState[stateList.size()]); + + // Init deprecated + SIGN = OAK_SIGN; + WALL_SIGN = OAK_WALL_SIGN; } catch (Throwable e) { e.printStackTrace(); throw new RuntimeException(e); @@ -858,7 +946,7 @@ public final class BlockTypes { // Get the enum name (remove namespace if minecraft:) int propStart = id.indexOf('['); String typeName = id.substring(0, propStart == -1 ? id.length() : propStart); - String enumName = (typeName.startsWith("minecraft:") ? typeName.substring(10) : typeName).toUpperCase(); + String enumName = (typeName.startsWith("minecraft:") ? typeName.substring(10) : typeName).toUpperCase(Locale.ROOT); BlockType existing = new BlockType(id, internalId, states); @@ -888,7 +976,7 @@ public final class BlockTypes { */ public static BlockType parse(final String type) throws InputParseException { - final String inputLower = type.toLowerCase(); + final String inputLower = type.toLowerCase(Locale.ROOT); String input = inputLower; if (!input.split("\\[", 2)[0].contains(":")) input = "minecraft:" + input; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/ImmutableBaseBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/ImmutableBaseBlock.java new file mode 100644 index 000000000..708e9c70e --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/ImmutableBaseBlock.java @@ -0,0 +1,50 @@ +package com.sk89q.worldedit.world.block; + +import com.boydti.fawe.beta.FilterBlock; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.registry.state.Property; + +import javax.annotation.Nullable; + +public final class ImmutableBaseBlock extends BaseBlock { + public ImmutableBaseBlock(BlockState blockState) { + super(blockState); + } + + @Nullable + @Override + public CompoundTag getNbtData() { + return null; + } + + @Override + public boolean hasNbtData() { + return false; + } + + @Override + public String getNbtId() { + return ""; + } + + @Override + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + return set.setBlock(extent, toBlockState()); + } + + @Override + public BaseBlock with(Property property, V value) { + return toImmutableState().with(property, value).toBaseBlock(); + } + + @Override + public BaseBlock toBaseBlock(CompoundTag compoundTag) { + if (compoundTag != null) { + return new BaseBlock(this.toImmutableState(), compoundTag); + } + return this; + } +} diff --git a/worldedit-core/src/main/java/net/jpountz/util/UnsafeUtils.java b/worldedit-core/src/main/java/net/jpountz/util/UnsafeUtils.java new file mode 100644 index 000000000..665616011 --- /dev/null +++ b/worldedit-core/src/main/java/net/jpountz/util/UnsafeUtils.java @@ -0,0 +1,151 @@ +package net.jpountz.util; + +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.lang.reflect.Field; +import java.nio.ByteOrder; +import sun.misc.Unsafe; + + +import static net.jpountz.util.Utils.NATIVE_BYTE_ORDER; + +public enum UnsafeUtils { + ; + + private static final Unsafe UNSAFE; + private static final long BYTE_ARRAY_OFFSET; + private static final int BYTE_ARRAY_SCALE; + private static final long INT_ARRAY_OFFSET; + private static final int INT_ARRAY_SCALE; + private static final long SHORT_ARRAY_OFFSET; + private static final int SHORT_ARRAY_SCALE; + + static { + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + UNSAFE = (Unsafe) theUnsafe.get(null); + BYTE_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(byte[].class); + BYTE_ARRAY_SCALE = UNSAFE.arrayIndexScale(byte[].class); + INT_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(int[].class); + INT_ARRAY_SCALE = UNSAFE.arrayIndexScale(int[].class); + SHORT_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(short[].class); + SHORT_ARRAY_SCALE = UNSAFE.arrayIndexScale(short[].class); + } catch (IllegalAccessException e) { + throw new ExceptionInInitializerError("Cannot access Unsafe"); + } catch (NoSuchFieldException e) { + throw new ExceptionInInitializerError("Cannot access Unsafe"); + } catch (SecurityException e) { + throw new ExceptionInInitializerError("Cannot access Unsafe"); + } + } + + public static void checkRange(byte[] buf, int off) { + SafeUtils.checkRange(buf, off); + } + + public static void checkRange(byte[] buf, int off, int len) { + SafeUtils.checkRange(buf, off, len); + } + + public static void checkLength(int len) { + SafeUtils.checkLength(len); + } + + public static byte readByte(byte[] src, int srcOff) { + return UNSAFE.getByte(src, BYTE_ARRAY_OFFSET + BYTE_ARRAY_SCALE * srcOff); + } + + public static void writeByte(byte[] src, int srcOff, byte value) { + UNSAFE.putByte(src, BYTE_ARRAY_OFFSET + BYTE_ARRAY_SCALE * srcOff, (byte) value); + } + + public static void writeByte(byte[] src, int srcOff, int value) { + writeByte(src, srcOff, (byte) value); + } + + public static long readLong(byte[] src, int srcOff) { + return UNSAFE.getLong(src, BYTE_ARRAY_OFFSET + srcOff); + } + + public static long readLongLE(byte[] src, int srcOff) { + long i = readLong(src, srcOff); + if (NATIVE_BYTE_ORDER == ByteOrder.BIG_ENDIAN) { + i = Long.reverseBytes(i); + } + return i; + } + + public static void writeLong(byte[] dest, int destOff, long value) { + UNSAFE.putLong(dest, BYTE_ARRAY_OFFSET + destOff, value); + } + + public static int readInt(byte[] src, int srcOff) { + return UNSAFE.getInt(src, BYTE_ARRAY_OFFSET + srcOff); + } + + public static int readIntLE(byte[] src, int srcOff) { + int i = readInt(src, srcOff); + if (NATIVE_BYTE_ORDER == ByteOrder.BIG_ENDIAN) { + i = Integer.reverseBytes(i); + } + return i; + } + + public static void writeInt(byte[] dest, int destOff, int value) { + UNSAFE.putInt(dest, BYTE_ARRAY_OFFSET + destOff, value); + } + + public static short readShort(byte[] src, int srcOff) { + return UNSAFE.getShort(src, BYTE_ARRAY_OFFSET + srcOff); + } + + public static int readShortLE(byte[] src, int srcOff) { + short s = readShort(src, srcOff); + if (NATIVE_BYTE_ORDER == ByteOrder.BIG_ENDIAN) { + s = Short.reverseBytes(s); + } + return s & 0xFFFF; + } + + public static void writeShort(byte[] dest, int destOff, short value) { + UNSAFE.putShort(dest, BYTE_ARRAY_OFFSET + destOff, value); + } + + public static void writeShortLE(byte[] buf, int off, int v) { + writeByte(buf, off, (byte) v); + writeByte(buf, off + 1, (byte) (v >>> 8)); + } + + public static int readInt(int[] src, int srcOff) { + return UNSAFE.getInt(src, INT_ARRAY_OFFSET + INT_ARRAY_SCALE * srcOff); + } + + public static void writeInt(int[] dest, int destOff, int value) { + UNSAFE.putInt(dest, INT_ARRAY_OFFSET + INT_ARRAY_SCALE * destOff, value); + } + + public static int readShort(short[] src, int srcOff) { + return UNSAFE.getShort(src, SHORT_ARRAY_OFFSET + SHORT_ARRAY_SCALE * srcOff) & 0xFFFF; + } + + public static void writeShort(short[] dest, int destOff, int value) { + UNSAFE.putShort(dest, SHORT_ARRAY_OFFSET + SHORT_ARRAY_SCALE * destOff, (short) value); + } + + public static Unsafe getUNSAFE() { + return UNSAFE; + } +} diff --git a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.json b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.json index 93dffaf2d..d5f98648d 100644 --- a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.json +++ b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.json @@ -224,6 +224,31 @@ "hasContainer": false } }, + { + "id": "minecraft:acacia_sign", + "localizedName": "Acacia Sign", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:acacia_slab", "localizedName": "Acacia Slab", @@ -258,7 +283,7 @@ "hardness": 2.0, "resistance": 3.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -299,6 +324,31 @@ "hasContainer": false } }, + { + "id": "minecraft:acacia_wall_sign", + "localizedName": "Acacia Sign", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:acacia_wood", "localizedName": "Acacia Wood", @@ -424,6 +474,81 @@ "hasContainer": false } }, + { + "id": "minecraft:andesite_slab", + "localizedName": "Andesite Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:andesite_stairs", + "localizedName": "Andesite Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:andesite_wall", + "localizedName": "Andesite Wall", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:anvil", "localizedName": "Anvil", @@ -524,6 +649,81 @@ "hasContainer": false } }, + { + "id": "minecraft:bamboo", + "localizedName": "Bamboo", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:bamboo_sapling", + "localizedName": "Bamboo Sapling", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": false, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:barrel", + "localizedName": "Barrel", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.5, + "resistance": 2.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": true + } + }, { "id": "minecraft:barrier", "localizedName": "Barrier", @@ -558,7 +758,7 @@ "hardness": 3.0, "resistance": 3.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -571,7 +771,7 @@ "unpushable": false, "mapColor": "#000000", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -624,6 +824,31 @@ "hasContainer": false } }, + { + "id": "minecraft:bell", + "localizedName": "Bell", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 5.0, + "resistance": 5.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:birch_button", "localizedName": "Birch Button", @@ -849,6 +1074,31 @@ "hasContainer": false } }, + { + "id": "minecraft:birch_sign", + "localizedName": "Birch Sign", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:birch_slab", "localizedName": "Birch Slab", @@ -883,7 +1133,7 @@ "hardness": 2.0, "resistance": 3.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -924,6 +1174,31 @@ "hasContainer": false } }, + { + "id": "minecraft:birch_wall_sign", + "localizedName": "Birch Sign", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:birch_wood", "localizedName": "Birch Wood", @@ -971,7 +1246,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -1108,7 +1383,7 @@ "hardness": 2.0, "resistance": 2.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -1116,10 +1391,10 @@ "burnable": false, "opaque": true, "replacedDuringPlacement": false, - "toolRequired": true, + "toolRequired": false, "fragileWhenPushed": false, "unpushable": false, - "mapColor": "#707070", + "mapColor": "#7f3fb2", "isTranslucent": true, "hasContainer": true } @@ -1133,7 +1408,7 @@ "hardness": 0.3, "resistance": 0.3, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -1201,7 +1476,7 @@ }, { "id": "minecraft:black_wall_banner", - "localizedName": "Air", + "localizedName": "Black Banner", "material": { "powerSource": false, "lightValue": 0, @@ -1221,7 +1496,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -1249,6 +1524,31 @@ "hasContainer": false } }, + { + "id": "minecraft:blast_furnace", + "localizedName": "Blast Furnace", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.5, + "resistance": 3.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": true + } + }, { "id": "minecraft:blue_banner", "localizedName": "Blue Banner", @@ -1271,7 +1571,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -1458,7 +1758,7 @@ "hardness": 2.0, "resistance": 2.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -1466,10 +1766,10 @@ "burnable": false, "opaque": true, "replacedDuringPlacement": false, - "toolRequired": true, + "toolRequired": false, "fragileWhenPushed": false, "unpushable": false, - "mapColor": "#707070", + "mapColor": "#7f3fb2", "isTranslucent": true, "hasContainer": true } @@ -1483,7 +1783,7 @@ "hardness": 0.3, "resistance": 0.3, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -1551,7 +1851,7 @@ }, { "id": "minecraft:blue_wall_banner", - "localizedName": "Air", + "localizedName": "Blue Banner", "material": { "powerSource": false, "lightValue": 0, @@ -1571,7 +1871,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -1802,6 +2102,31 @@ { "id": "minecraft:brick_stairs", "localizedName": "Brick Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:brick_wall", + "localizedName": "Brick Wall", "material": { "powerSource": false, "lightValue": 0, @@ -1871,7 +2196,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -2058,7 +2383,7 @@ "hardness": 2.0, "resistance": 2.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -2066,10 +2391,10 @@ "burnable": false, "opaque": true, "replacedDuringPlacement": false, - "toolRequired": true, + "toolRequired": false, "fragileWhenPushed": false, "unpushable": false, - "mapColor": "#707070", + "mapColor": "#7f3fb2", "isTranslucent": true, "hasContainer": true } @@ -2083,7 +2408,7 @@ "hardness": 0.3, "resistance": 0.3, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -2151,7 +2476,7 @@ }, { "id": "minecraft:brown_wall_banner", - "localizedName": "Air", + "localizedName": "Brown Banner", "material": { "powerSource": false, "lightValue": 0, @@ -2171,7 +2496,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -2374,6 +2699,31 @@ "hasContainer": false } }, + { + "id": "minecraft:campfire", + "localizedName": "Campfire", + "material": { + "powerSource": false, + "lightValue": 15, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": true + } + }, { "id": "minecraft:carrots", "localizedName": "Carrots", @@ -2399,6 +2749,31 @@ "hasContainer": false } }, + { + "id": "minecraft:cartography_table", + "localizedName": "Cartography Table", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.5, + "resistance": 2.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:carved_pumpkin", "localizedName": "Carved Pumpkin", @@ -2433,7 +2808,7 @@ "hardness": 2.0, "resistance": 2.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -2496,7 +2871,7 @@ "unpushable": false, "mapColor": "#a7a7a7", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -2658,7 +3033,7 @@ "hardness": 0.4, "resistance": 0.4, "ticksRandomly": true, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": false, @@ -2858,7 +3233,7 @@ "hardness": 2.0, "resistance": 6.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -2908,7 +3283,7 @@ "hardness": 4.0, "resistance": 4.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -2971,7 +3346,7 @@ "unpushable": false, "mapColor": "#a7a7a7", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -2999,6 +3374,31 @@ "hasContainer": false } }, + { + "id": "minecraft:composter", + "localizedName": "Composter", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.6, + "resistance": 0.6, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:conduit", "localizedName": "Conduit", @@ -3021,7 +3421,32 @@ "unpushable": false, "mapColor": "#000000", "isTranslucent": false, - "hasContainer": true + "hasContainer": false + } + }, + { + "id": "minecraft:cornflower", + "localizedName": "Cornflower", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false } }, { @@ -3096,12 +3521,12 @@ "unpushable": false, "mapColor": "#000000", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { "id": "minecraft:creeper_wall_head", - "localizedName": "Air", + "localizedName": "Creeper Head", "material": { "powerSource": false, "lightValue": 0, @@ -3121,7 +3546,7 @@ "unpushable": false, "mapColor": "#000000", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -3149,6 +3574,31 @@ "hasContainer": false } }, + { + "id": "minecraft:cut_red_sandstone_slab", + "localizedName": "Cut Red Sandstone Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:cut_sandstone", "localizedName": "Cut Sandstone", @@ -3174,6 +3624,31 @@ "hasContainer": false } }, + { + "id": "minecraft:cut_sandstone_slab", + "localizedName": "Cut Sandstone Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:cyan_banner", "localizedName": "Cyan Banner", @@ -3196,7 +3671,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -3333,7 +3808,7 @@ "hardness": 2.0, "resistance": 2.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -3341,10 +3816,10 @@ "burnable": false, "opaque": true, "replacedDuringPlacement": false, - "toolRequired": true, + "toolRequired": false, "fragileWhenPushed": false, "unpushable": false, - "mapColor": "#707070", + "mapColor": "#7f3fb2", "isTranslucent": true, "hasContainer": true } @@ -3358,7 +3833,7 @@ "hardness": 0.3, "resistance": 0.3, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -3426,7 +3901,7 @@ }, { "id": "minecraft:cyan_wall_banner", - "localizedName": "Air", + "localizedName": "Cyan Banner", "material": { "powerSource": false, "lightValue": 0, @@ -3446,7 +3921,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -3749,6 +4224,31 @@ "hasContainer": false } }, + { + "id": "minecraft:dark_oak_sign", + "localizedName": "Dark Oak Sign", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:dark_oak_slab", "localizedName": "Dark Oak Slab", @@ -3783,7 +4283,7 @@ "hardness": 2.0, "resistance": 3.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -3824,6 +4324,31 @@ "hasContainer": false } }, + { + "id": "minecraft:dark_oak_wall_sign", + "localizedName": "Dark Oak Sign", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:dark_oak_wood", "localizedName": "Dark Oak Wood", @@ -3908,7 +4433,7 @@ "hardness": 1.5, "resistance": 6.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -3946,7 +4471,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -4574,6 +5099,81 @@ "hasContainer": false } }, + { + "id": "minecraft:diorite_slab", + "localizedName": "Diorite Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:diorite_stairs", + "localizedName": "Diorite Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:diorite_wall", + "localizedName": "Diorite Wall", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:dirt", "localizedName": "Dirt", @@ -4671,12 +5271,12 @@ "unpushable": false, "mapColor": "#000000", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { "id": "minecraft:dragon_wall_head", - "localizedName": "Air", + "localizedName": "Dragon Head", "material": { "powerSource": false, "lightValue": 0, @@ -4696,7 +5296,7 @@ "unpushable": false, "mapColor": "#000000", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -4821,7 +5421,7 @@ "unpushable": false, "mapColor": "#707070", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -4833,7 +5433,7 @@ "hardness": -1.0, "resistance": 3600000.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": false, @@ -4846,7 +5446,7 @@ "unpushable": true, "mapColor": "#000000", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -4871,7 +5471,7 @@ "unpushable": true, "mapColor": "#000000", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -4949,6 +5549,81 @@ "hasContainer": false } }, + { + "id": "minecraft:end_stone_brick_slab", + "localizedName": "End Stone Brick Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:end_stone_brick_stairs", + "localizedName": "End Stone Brick Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:end_stone_brick_wall", + "localizedName": "End Stone Brick Wall", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:end_stone_bricks", "localizedName": "End Stone Bricks", @@ -4996,7 +5671,7 @@ "unpushable": false, "mapColor": "#707070", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -5174,6 +5849,31 @@ "hasContainer": false } }, + { + "id": "minecraft:fletching_table", + "localizedName": "Fletching Table", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.5, + "resistance": 2.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:flower_pot", "localizedName": "Flower Pot", @@ -5258,7 +5958,7 @@ "hardness": 0.3, "resistance": 0.3, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -5399,6 +6099,81 @@ "hasContainer": false } }, + { + "id": "minecraft:granite_slab", + "localizedName": "Granite Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:granite_stairs", + "localizedName": "Granite Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:granite_wall", + "localizedName": "Granite Wall", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:grass", "localizedName": "Grass", @@ -5521,7 +6296,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -5658,7 +6433,7 @@ "hardness": 2.0, "resistance": 2.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -5666,10 +6441,10 @@ "burnable": false, "opaque": true, "replacedDuringPlacement": false, - "toolRequired": true, + "toolRequired": false, "fragileWhenPushed": false, "unpushable": false, - "mapColor": "#707070", + "mapColor": "#7f3fb2", "isTranslucent": true, "hasContainer": true } @@ -5683,7 +6458,7 @@ "hardness": 0.3, "resistance": 0.3, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -5751,7 +6526,7 @@ }, { "id": "minecraft:gray_wall_banner", - "localizedName": "Air", + "localizedName": "Gray Banner", "material": { "powerSource": false, "lightValue": 0, @@ -5771,7 +6546,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -5821,7 +6596,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -5958,7 +6733,7 @@ "hardness": 2.0, "resistance": 2.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -5966,10 +6741,10 @@ "burnable": false, "opaque": true, "replacedDuringPlacement": false, - "toolRequired": true, + "toolRequired": false, "fragileWhenPushed": false, "unpushable": false, - "mapColor": "#707070", + "mapColor": "#7f3fb2", "isTranslucent": true, "hasContainer": true } @@ -5983,7 +6758,7 @@ "hardness": 0.3, "resistance": 0.3, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -6051,7 +6826,7 @@ }, { "id": "minecraft:green_wall_banner", - "localizedName": "Air", + "localizedName": "Green Banner", "material": { "powerSource": false, "lightValue": 0, @@ -6071,7 +6846,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -6099,6 +6874,31 @@ "hasContainer": false } }, + { + "id": "minecraft:grindstone", + "localizedName": "Grindstone", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": true, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:hay_block", "localizedName": "Hay Bale", @@ -6158,7 +6958,7 @@ "hardness": 3.0, "resistance": 4.8, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -6599,6 +7399,31 @@ "hasContainer": false } }, + { + "id": "minecraft:jigsaw", + "localizedName": "Jigsaw Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": -1.0, + "resistance": 3600000.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:jukebox", "localizedName": "Jukebox", @@ -6849,6 +7674,31 @@ "hasContainer": false } }, + { + "id": "minecraft:jungle_sign", + "localizedName": "Jungle Sign", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:jungle_slab", "localizedName": "Jungle Slab", @@ -6883,7 +7733,7 @@ "hardness": 2.0, "resistance": 3.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -6924,6 +7774,31 @@ "hasContainer": false } }, + { + "id": "minecraft:jungle_wall_sign", + "localizedName": "Jungle Sign", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:jungle_wood", "localizedName": "Jungle Wood", @@ -6983,7 +7858,7 @@ "hardness": 0.0, "resistance": 0.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": false, @@ -7024,6 +7899,31 @@ "hasContainer": false } }, + { + "id": "minecraft:lantern", + "localizedName": "Lantern", + "material": { + "powerSource": false, + "lightValue": 15, + "hardness": 3.5, + "resistance": 3.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:lapis_block", "localizedName": "Lapis Lazuli Block", @@ -7083,7 +7983,7 @@ "hardness": 0.0, "resistance": 0.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": false, @@ -7124,6 +8024,31 @@ "hasContainer": false } }, + { + "id": "minecraft:lectern", + "localizedName": "Lectern", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 2.5, + "resistance": 2.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": true + } + }, { "id": "minecraft:lever", "localizedName": "Lever", @@ -7171,7 +8096,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -7308,7 +8233,7 @@ "hardness": 2.0, "resistance": 2.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -7316,10 +8241,10 @@ "burnable": false, "opaque": true, "replacedDuringPlacement": false, - "toolRequired": true, + "toolRequired": false, "fragileWhenPushed": false, "unpushable": false, - "mapColor": "#707070", + "mapColor": "#7f3fb2", "isTranslucent": true, "hasContainer": true } @@ -7333,7 +8258,7 @@ "hardness": 0.3, "resistance": 0.3, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -7401,7 +8326,7 @@ }, { "id": "minecraft:light_blue_wall_banner", - "localizedName": "Air", + "localizedName": "Light Blue Banner", "material": { "powerSource": false, "lightValue": 0, @@ -7421,7 +8346,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -7471,7 +8396,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -7608,7 +8533,7 @@ "hardness": 2.0, "resistance": 2.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -7616,10 +8541,10 @@ "burnable": false, "opaque": true, "replacedDuringPlacement": false, - "toolRequired": true, + "toolRequired": false, "fragileWhenPushed": false, "unpushable": false, - "mapColor": "#707070", + "mapColor": "#7f3fb2", "isTranslucent": true, "hasContainer": true } @@ -7633,7 +8558,7 @@ "hardness": 0.3, "resistance": 0.3, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -7701,7 +8626,7 @@ }, { "id": "minecraft:light_gray_wall_banner", - "localizedName": "Air", + "localizedName": "Light Gray Banner", "material": { "powerSource": false, "lightValue": 0, @@ -7721,7 +8646,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -7783,7 +8708,7 @@ "hardness": 0.0, "resistance": 0.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": false, @@ -7799,6 +8724,31 @@ "hasContainer": false } }, + { + "id": "minecraft:lily_of_the_valley", + "localizedName": "Lily of the Valley", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:lily_pad", "localizedName": "Lily Pad", @@ -7846,7 +8796,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -7983,7 +8933,7 @@ "hardness": 2.0, "resistance": 2.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -7991,10 +8941,10 @@ "burnable": false, "opaque": true, "replacedDuringPlacement": false, - "toolRequired": true, + "toolRequired": false, "fragileWhenPushed": false, "unpushable": false, - "mapColor": "#707070", + "mapColor": "#7f3fb2", "isTranslucent": true, "hasContainer": true } @@ -8008,7 +8958,7 @@ "hardness": 0.3, "resistance": 0.3, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -8076,7 +9026,7 @@ }, { "id": "minecraft:lime_wall_banner", - "localizedName": "Air", + "localizedName": "Lime Banner", "material": { "powerSource": false, "lightValue": 0, @@ -8096,7 +9046,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -8124,6 +9074,31 @@ "hasContainer": false } }, + { + "id": "minecraft:loom", + "localizedName": "Loom", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.5, + "resistance": 2.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:magenta_banner", "localizedName": "Magenta Banner", @@ -8146,7 +9121,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -8283,7 +9258,7 @@ "hardness": 2.0, "resistance": 2.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -8291,10 +9266,10 @@ "burnable": false, "opaque": true, "replacedDuringPlacement": false, - "toolRequired": true, + "toolRequired": false, "fragileWhenPushed": false, "unpushable": false, - "mapColor": "#707070", + "mapColor": "#7f3fb2", "isTranslucent": true, "hasContainer": true } @@ -8308,7 +9283,7 @@ "hardness": 0.3, "resistance": 0.3, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -8376,7 +9351,7 @@ }, { "id": "minecraft:magenta_wall_banner", - "localizedName": "Air", + "localizedName": "Magenta Banner", "material": { "powerSource": false, "lightValue": 0, @@ -8396,7 +9371,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -8524,6 +9499,56 @@ "hasContainer": false } }, + { + "id": "minecraft:mossy_cobblestone_slab", + "localizedName": "Mossy Cobblestone Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:mossy_cobblestone_stairs", + "localizedName": "Mossy Cobblestone Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:mossy_cobblestone_wall", "localizedName": "Mossy Cobblestone Wall", @@ -8549,6 +9574,81 @@ "hasContainer": false } }, + { + "id": "minecraft:mossy_stone_brick_slab", + "localizedName": "Mossy Stone Brick Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:mossy_stone_brick_stairs", + "localizedName": "Mossy Stone Brick Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:mossy_stone_brick_wall", + "localizedName": "Mossy Stone Brick Wall", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:mossy_stone_bricks", "localizedName": "Mossy Stone Bricks", @@ -8596,7 +9696,7 @@ "unpushable": true, "mapColor": "#707070", "isTranslucent": true, - "hasContainer": true + "hasContainer": false } }, { @@ -8702,6 +9802,31 @@ { "id": "minecraft:nether_brick_stairs", "localizedName": "Nether Brick Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:nether_brick_wall", + "localizedName": "Nether Brick Wall", "material": { "powerSource": false, "lightValue": 0, @@ -9124,6 +10249,31 @@ "hasContainer": false } }, + { + "id": "minecraft:oak_sign", + "localizedName": "Oak Sign", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:oak_slab", "localizedName": "Oak Slab", @@ -9158,7 +10308,7 @@ "hardness": 2.0, "resistance": 3.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -9199,6 +10349,31 @@ "hasContainer": false } }, + { + "id": "minecraft:oak_wall_sign", + "localizedName": "Oak Sign", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:oak_wood", "localizedName": "Oak Wood", @@ -9296,7 +10471,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -9433,7 +10608,7 @@ "hardness": 2.0, "resistance": 2.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -9441,10 +10616,10 @@ "burnable": false, "opaque": true, "replacedDuringPlacement": false, - "toolRequired": true, + "toolRequired": false, "fragileWhenPushed": false, "unpushable": false, - "mapColor": "#707070", + "mapColor": "#7f3fb2", "isTranslucent": true, "hasContainer": true } @@ -9458,7 +10633,7 @@ "hardness": 0.3, "resistance": 0.3, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -9551,7 +10726,7 @@ }, { "id": "minecraft:orange_wall_banner", - "localizedName": "Air", + "localizedName": "Orange Banner", "material": { "powerSource": false, "lightValue": 0, @@ -9571,7 +10746,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -9658,7 +10833,7 @@ "hardness": 0.0, "resistance": 0.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": false, @@ -9721,7 +10896,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -9858,7 +11033,7 @@ "hardness": 2.0, "resistance": 2.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -9866,10 +11041,10 @@ "burnable": false, "opaque": true, "replacedDuringPlacement": false, - "toolRequired": true, + "toolRequired": false, "fragileWhenPushed": false, "unpushable": false, - "mapColor": "#707070", + "mapColor": "#7f3fb2", "isTranslucent": true, "hasContainer": true } @@ -9883,7 +11058,7 @@ "hardness": 0.3, "resistance": 0.3, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -9976,7 +11151,7 @@ }, { "id": "minecraft:pink_wall_banner", - "localizedName": "Air", + "localizedName": "Pink Banner", "material": { "powerSource": false, "lightValue": 0, @@ -9996,7 +11171,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -10033,7 +11208,7 @@ "hardness": 0.5, "resistance": 0.5, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -10096,12 +11271,12 @@ "unpushable": false, "mapColor": "#000000", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { "id": "minecraft:player_wall_head", - "localizedName": "Air", + "localizedName": "Player Head", "material": { "powerSource": false, "lightValue": 0, @@ -10121,7 +11296,7 @@ "unpushable": false, "mapColor": "#000000", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -10174,6 +11349,56 @@ "hasContainer": false } }, + { + "id": "minecraft:polished_andesite_slab", + "localizedName": "Polished Andesite Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:polished_andesite_stairs", + "localizedName": "Polished Andesite Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:polished_diorite", "localizedName": "Polished Diorite", @@ -10199,6 +11424,56 @@ "hasContainer": false } }, + { + "id": "minecraft:polished_diorite_slab", + "localizedName": "Polished Diorite Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:polished_diorite_stairs", + "localizedName": "Polished Diorite Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:polished_granite", "localizedName": "Polished Granite", @@ -10224,6 +11499,56 @@ "hasContainer": false } }, + { + "id": "minecraft:polished_granite_slab", + "localizedName": "Polished Granite Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:polished_granite_stairs", + "localizedName": "Polished Granite Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:poppy", "localizedName": "Poppy", @@ -10349,6 +11674,31 @@ "hasContainer": false } }, + { + "id": "minecraft:potted_bamboo", + "localizedName": "Potted Bamboo", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:potted_birch_sapling", "localizedName": "Potted Birch Sapling", @@ -10449,6 +11799,31 @@ "hasContainer": false } }, + { + "id": "minecraft:potted_cornflower", + "localizedName": "Potted Cornflower", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:potted_dandelion", "localizedName": "Potted Dandelion", @@ -10574,6 +11949,31 @@ "hasContainer": false } }, + { + "id": "minecraft:potted_lily_of_the_valley", + "localizedName": "Potted Lily of the Valley", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:potted_oak_sapling", "localizedName": "Potted Oak Sapling", @@ -10799,6 +12199,31 @@ "hasContainer": false } }, + { + "id": "minecraft:potted_wither_rose", + "localizedName": "Potted Wither Rose", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:powered_rail", "localizedName": "Powered Rail", @@ -10883,7 +12308,7 @@ "hardness": 1.5, "resistance": 6.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -10952,6 +12377,31 @@ { "id": "minecraft:prismarine_stairs", "localizedName": "Prismarine Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:prismarine_wall", + "localizedName": "Prismarine Wall", "material": { "powerSource": false, "lightValue": 0, @@ -11046,7 +12496,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -11183,7 +12633,7 @@ "hardness": 2.0, "resistance": 2.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -11191,10 +12641,10 @@ "burnable": false, "opaque": true, "replacedDuringPlacement": false, - "toolRequired": true, + "toolRequired": false, "fragileWhenPushed": false, "unpushable": false, - "mapColor": "#707070", + "mapColor": "#7f3fb2", "isTranslucent": true, "hasContainer": true } @@ -11208,7 +12658,7 @@ "hardness": 0.3, "resistance": 0.3, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -11276,7 +12726,7 @@ }, { "id": "minecraft:purple_wall_banner", - "localizedName": "Air", + "localizedName": "Purple Banner", "material": { "powerSource": false, "lightValue": 0, @@ -11296,7 +12746,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -11408,7 +12858,7 @@ "hardness": 1.5, "resistance": 6.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -11508,7 +12958,7 @@ "hardness": 0.8, "resistance": 0.8, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -11571,7 +13021,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -11749,6 +13199,81 @@ "hasContainer": false } }, + { + "id": "minecraft:red_nether_brick_slab", + "localizedName": "Red Nether Brick Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_nether_brick_stairs", + "localizedName": "Red Nether Brick Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_nether_brick_wall", + "localizedName": "Red Nether Brick Wall", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:red_nether_bricks", "localizedName": "Red Nether Bricks", @@ -11852,6 +13377,31 @@ { "id": "minecraft:red_sandstone_stairs", "localizedName": "Red Sandstone Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_sandstone_wall", + "localizedName": "Red Sandstone Wall", "material": { "powerSource": false, "lightValue": 0, @@ -11883,7 +13433,7 @@ "hardness": 2.0, "resistance": 2.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -11891,10 +13441,10 @@ "burnable": false, "opaque": true, "replacedDuringPlacement": false, - "toolRequired": true, + "toolRequired": false, "fragileWhenPushed": false, "unpushable": false, - "mapColor": "#707070", + "mapColor": "#7f3fb2", "isTranslucent": true, "hasContainer": true } @@ -11908,7 +13458,7 @@ "hardness": 0.3, "resistance": 0.3, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -12001,7 +13551,7 @@ }, { "id": "minecraft:red_wall_banner", - "localizedName": "Air", + "localizedName": "Red Banner", "material": { "powerSource": false, "lightValue": 0, @@ -12021,7 +13571,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -12151,7 +13701,7 @@ }, { "id": "minecraft:redstone_wall_torch", - "localizedName": "Air", + "localizedName": "Redstone Torch", "material": { "powerSource": true, "lightValue": 7, @@ -12176,7 +13726,7 @@ }, { "id": "minecraft:redstone_wire", - "localizedName": "Redstone Dust", + "localizedName": "Redstone Wire", "material": { "powerSource": true, "lightValue": 0, @@ -12246,7 +13796,7 @@ "unpushable": false, "mapColor": "#a7a7a7", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -12258,7 +13808,7 @@ "hardness": 0.0, "resistance": 0.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": false, @@ -12352,6 +13902,31 @@ { "id": "minecraft:sandstone_stairs", "localizedName": "Sandstone Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:sandstone_wall", + "localizedName": "Sandstone Wall", "material": { "powerSource": false, "lightValue": 0, @@ -12374,6 +13949,31 @@ "hasContainer": false } }, + { + "id": "minecraft:scaffolding", + "localizedName": "Scaffolding", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": true, + "hasContainer": false + } + }, { "id": "minecraft:sea_lantern", "localizedName": "Sea Lantern", @@ -12458,7 +14058,7 @@ "hardness": 2.0, "resistance": 2.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -12466,36 +14066,11 @@ "burnable": false, "opaque": true, "replacedDuringPlacement": false, - "toolRequired": true, - "fragileWhenPushed": false, - "unpushable": false, - "mapColor": "#707070", - "isTranslucent": true, - "hasContainer": true - } - }, - { - "id": "minecraft:sign", - "localizedName": "Sign", - "material": { - "powerSource": false, - "lightValue": 0, - "hardness": 1.0, - "resistance": 1.0, - "ticksRandomly": false, - "fullCube": false, - "slipperiness": 0.6, - "liquid": false, - "solid": true, - "movementBlocker": true, - "burnable": true, - "opaque": true, - "replacedDuringPlacement": false, "toolRequired": false, "fragileWhenPushed": false, "unpushable": false, - "mapColor": "#8f7748", - "isTranslucent": false, + "mapColor": "#7f3fb2", + "isTranslucent": true, "hasContainer": true } }, @@ -12521,12 +14096,12 @@ "unpushable": false, "mapColor": "#000000", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { "id": "minecraft:skeleton_wall_skull", - "localizedName": "Air", + "localizedName": "Skeleton Skull", "material": { "powerSource": false, "lightValue": 0, @@ -12546,7 +14121,7 @@ "unpushable": false, "mapColor": "#000000", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -12574,6 +14149,56 @@ "hasContainer": false } }, + { + "id": "minecraft:smithing_table", + "localizedName": "Smithing Table", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.5, + "resistance": 2.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:smoker", + "localizedName": "Smoker", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.5, + "resistance": 3.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": true + } + }, { "id": "minecraft:smooth_quartz", "localizedName": "Smooth Quartz", @@ -12599,6 +14224,56 @@ "hasContainer": false } }, + { + "id": "minecraft:smooth_quartz_slab", + "localizedName": "Smooth Quartz Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:smooth_quartz_stairs", + "localizedName": "Smooth Quartz Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:smooth_red_sandstone", "localizedName": "Smooth Red Sandstone", @@ -12624,6 +14299,56 @@ "hasContainer": false } }, + { + "id": "minecraft:smooth_red_sandstone_slab", + "localizedName": "Smooth Red Sandstone Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:smooth_red_sandstone_stairs", + "localizedName": "Smooth Red Sandstone Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:smooth_sandstone", "localizedName": "Smooth Sandstone", @@ -12649,6 +14374,56 @@ "hasContainer": false } }, + { + "id": "minecraft:smooth_sandstone_slab", + "localizedName": "Smooth Sandstone Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:smooth_sandstone_stairs", + "localizedName": "Smooth Sandstone Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:smooth_stone", "localizedName": "Smooth Stone", @@ -12674,6 +14449,31 @@ "hasContainer": false } }, + { + "id": "minecraft:smooth_stone_slab", + "localizedName": "Smooth Stone Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:snow", "localizedName": "Snow", @@ -12707,7 +14507,7 @@ "lightValue": 0, "hardness": 0.2, "resistance": 0.2, - "ticksRandomly": true, + "ticksRandomly": false, "fullCube": true, "slipperiness": 0.6, "liquid": false, @@ -12771,7 +14571,7 @@ "unpushable": false, "mapColor": "#707070", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -13024,6 +14824,31 @@ "hasContainer": false } }, + { + "id": "minecraft:spruce_sign", + "localizedName": "Spruce Sign", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:spruce_slab", "localizedName": "Spruce Slab", @@ -13058,7 +14883,7 @@ "hardness": 2.0, "resistance": 3.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -13099,6 +14924,31 @@ "hasContainer": false } }, + { + "id": "minecraft:spruce_wall_sign", + "localizedName": "Spruce Sign", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:spruce_wood", "localizedName": "Spruce Wood", @@ -13133,7 +14983,7 @@ "hardness": 0.5, "resistance": 0.5, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -13202,6 +15052,31 @@ { "id": "minecraft:stone_brick_stairs", "localizedName": "Stone Brick Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:stone_brick_wall", + "localizedName": "Stone Brick Wall", "material": { "powerSource": false, "lightValue": 0, @@ -13324,6 +15199,56 @@ "hasContainer": false } }, + { + "id": "minecraft:stone_stairs", + "localizedName": "Stone Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:stonecutter", + "localizedName": "Stonecutter", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.5, + "resistance": 3.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:stripped_acacia_log", "localizedName": "Stripped Acacia Log", @@ -13646,7 +15571,7 @@ "unpushable": false, "mapColor": "#a7a7a7", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -13708,7 +15633,7 @@ "hardness": 0.0, "resistance": 0.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": false, @@ -13724,6 +15649,31 @@ "hasContainer": false } }, + { + "id": "minecraft:sweet_berry_bush", + "localizedName": "Sweet Berry Bush", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:tall_grass", "localizedName": "Tall Grass", @@ -13733,7 +15683,7 @@ "hardness": 0.0, "resistance": 0.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": false, @@ -14099,34 +16049,9 @@ "hasContainer": false } }, - { - "id": "minecraft:wall_sign", - "localizedName": "Air", - "material": { - "powerSource": false, - "lightValue": 0, - "hardness": 1.0, - "resistance": 1.0, - "ticksRandomly": false, - "fullCube": false, - "slipperiness": 0.6, - "liquid": false, - "solid": true, - "movementBlocker": true, - "burnable": true, - "opaque": true, - "replacedDuringPlacement": false, - "toolRequired": false, - "fragileWhenPushed": false, - "unpushable": false, - "mapColor": "#8f7748", - "isTranslucent": false, - "hasContainer": true - } - }, { "id": "minecraft:wall_torch", - "localizedName": "Air", + "localizedName": "Torch", "material": { "powerSource": false, "lightValue": 14, @@ -14246,7 +16171,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -14383,7 +16308,7 @@ "hardness": 2.0, "resistance": 2.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -14391,10 +16316,10 @@ "burnable": false, "opaque": true, "replacedDuringPlacement": false, - "toolRequired": true, + "toolRequired": false, "fragileWhenPushed": false, "unpushable": false, - "mapColor": "#707070", + "mapColor": "#7f3fb2", "isTranslucent": true, "hasContainer": true } @@ -14408,7 +16333,7 @@ "hardness": 0.3, "resistance": 0.3, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -14501,7 +16426,7 @@ }, { "id": "minecraft:white_wall_banner", - "localizedName": "Air", + "localizedName": "White Banner", "material": { "powerSource": false, "lightValue": 0, @@ -14521,7 +16446,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -14549,6 +16474,31 @@ "hasContainer": false } }, + { + "id": "minecraft:wither_rose", + "localizedName": "Wither Rose", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, { "id": "minecraft:wither_skeleton_skull", "localizedName": "Wither Skeleton Skull", @@ -14571,12 +16521,12 @@ "unpushable": false, "mapColor": "#000000", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { "id": "minecraft:wither_skeleton_wall_skull", - "localizedName": "Air", + "localizedName": "Wither Skeleton Skull", "material": { "powerSource": false, "lightValue": 0, @@ -14596,7 +16546,7 @@ "unpushable": false, "mapColor": "#000000", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -14621,7 +16571,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -14758,7 +16708,7 @@ "hardness": 2.0, "resistance": 2.0, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -14766,10 +16716,10 @@ "burnable": false, "opaque": true, "replacedDuringPlacement": false, - "toolRequired": true, + "toolRequired": false, "fragileWhenPushed": false, "unpushable": false, - "mapColor": "#707070", + "mapColor": "#7f3fb2", "isTranslucent": true, "hasContainer": true } @@ -14783,7 +16733,7 @@ "hardness": 0.3, "resistance": 0.3, "ticksRandomly": false, - "fullCube": false, + "fullCube": true, "slipperiness": 0.6, "liquid": false, "solid": true, @@ -14851,7 +16801,7 @@ }, { "id": "minecraft:yellow_wall_banner", - "localizedName": "Air", + "localizedName": "Yellow Banner", "material": { "powerSource": false, "lightValue": 0, @@ -14871,7 +16821,7 @@ "unpushable": false, "mapColor": "#8f7748", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { @@ -14921,12 +16871,12 @@ "unpushable": false, "mapColor": "#000000", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } }, { "id": "minecraft:zombie_wall_head", - "localizedName": "Air", + "localizedName": "Zombie Head", "material": { "powerSource": false, "lightValue": 0, @@ -14946,7 +16896,7 @@ "unpushable": false, "mapColor": "#000000", "isTranslucent": false, - "hasContainer": true + "hasContainer": false } } ] \ No newline at end of file diff --git a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/legacy.json b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/legacy.json index 10907d78e..9ba596968 100644 --- a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/legacy.json +++ b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/legacy.json @@ -413,22 +413,22 @@ "62:11": "minecraft:furnace[facing=south,lit=true]", "62:12": "minecraft:furnace[facing=west,lit=true]", "62:13": "minecraft:furnace[facing=east,lit=true]", - "63:0": "minecraft:sign[rotation=0]", - "63:1": "minecraft:sign[rotation=1]", - "63:2": "minecraft:sign[rotation=2]", - "63:3": "minecraft:sign[rotation=3]", - "63:4": "minecraft:sign[rotation=4]", - "63:5": "minecraft:sign[rotation=5]", - "63:6": "minecraft:sign[rotation=6]", - "63:7": "minecraft:sign[rotation=7]", - "63:8": "minecraft:sign[rotation=8]", - "63:9": "minecraft:sign[rotation=9]", - "63:10": "minecraft:sign[rotation=10]", - "63:11": "minecraft:sign[rotation=11]", - "63:12": "minecraft:sign[rotation=12]", - "63:13": "minecraft:sign[rotation=13]", - "63:14": "minecraft:sign[rotation=14]", - "63:15": "minecraft:sign[rotation=15]", + "63:0": "minecraft:oak_sign[rotation=0]", + "63:1": "minecraft:oak_sign[rotation=1]", + "63:2": "minecraft:oak_sign[rotation=2]", + "63:3": "minecraft:oak_sign[rotation=3]", + "63:4": "minecraft:oak_sign[rotation=4]", + "63:5": "minecraft:oak_sign[rotation=5]", + "63:6": "minecraft:oak_sign[rotation=6]", + "63:7": "minecraft:oak_sign[rotation=7]", + "63:8": "minecraft:oak_sign[rotation=8]", + "63:9": "minecraft:oak_sign[rotation=9]", + "63:10": "minecraft:oak_sign[rotation=10]", + "63:11": "minecraft:oak_sign[rotation=11]", + "63:12": "minecraft:oak_sign[rotation=12]", + "63:13": "minecraft:oak_sign[rotation=13]", + "63:14": "minecraft:oak_sign[rotation=14]", + "63:15": "minecraft:oak_sign[rotation=15]", "64:0": "minecraft:oak_door[hinge=right,half=lower,powered=false,facing=east,open=false]", "64:1": "minecraft:oak_door[hinge=right,half=lower,powered=false,facing=south,open=false]", "64:2": "minecraft:oak_door[hinge=right,half=lower,powered=false,facing=west,open=false]", @@ -468,15 +468,15 @@ "67:5": "minecraft:cobblestone_stairs[half=top,shape=straight,facing=west]", "67:6": "minecraft:cobblestone_stairs[half=top,shape=straight,facing=south]", "67:7": "minecraft:cobblestone_stairs[half=top,shape=straight,facing=north]", - "68:0": "minecraft:wall_sign", - "68:2": "minecraft:wall_sign[facing=north]", - "68:3": "minecraft:wall_sign[facing=south]", - "68:4": "minecraft:wall_sign[facing=west]", - "68:5": "minecraft:wall_sign[facing=east]", - "68:10": "minecraft:wall_sign[facing=north]", - "68:11": "minecraft:wall_sign[facing=south]", - "68:12": "minecraft:wall_sign[facing=west]", - "68:13": "minecraft:wall_sign[facing=east]", + "68:0": "minecraft:oak_wall_sign", + "68:2": "minecraft:oak_wall_sign[facing=north]", + "68:3": "minecraft:oak_wall_sign[facing=south]", + "68:4": "minecraft:oak_wall_sign[facing=west]", + "68:5": "minecraft:oak_wall_sign[facing=east]", + "68:10": "minecraft:oak_wall_sign[facing=north]", + "68:11": "minecraft:oak_wall_sign[facing=south]", + "68:12": "minecraft:oak_wall_sign[facing=west]", + "68:13": "minecraft:oak_wall_sign[facing=east]", "69:0": "minecraft:lever[powered=false,facing=north,face=ceiling]", "69:1": "minecraft:lever[powered=false,facing=east,face=wall]", "69:2": "minecraft:lever[powered=false,facing=west,face=wall]", @@ -2196,7 +2196,7 @@ "321:0": "minecraft:painting", "322:0": "minecraft:golden_apple", "322:1": "minecraft:enchanted_golden_apple", - "323:0": "minecraft:sign", + "323:0": "minecraft:oak_sign", "324:0": "minecraft:oak_door", "325:0": "minecraft:bucket", "326:0": "minecraft:water_bucket",