();
- m_blockFaces.put(0x1d, new Piston(m_tex, true)); //1d - Sticky piston
- m_blockFaces.put(0x21, new Piston(m_tex, false)); //21 - Piston
- m_blockFaces.put(0x22, new PistonExtension(m_tex)); //22 - Piston extended
- m_blockFaces.put(0x63, new Shroom(m_tex, 3)); //63 - Huge brow mushroom
- m_blockFaces.put(0x64, new Shroom(m_tex, 2)); //64 - Huge red mushroom
+ m_blockFaces = new HashMap<>();
+ m_blockFaces.put(Material.STICKY_PISTON, new Piston(m_tex, true)); //1d - Sticky piston
+ m_blockFaces.put(Material.PISTON, new Piston(m_tex, false)); //21 - Piston
+ m_blockFaces.put(Material.PISTON_HEAD, new PistonExtension(m_tex)); //22 - Piston extended
+ m_blockFaces.put(Material.BROWN_MUSHROOM_BLOCK, new Shroom(m_tex, 3)); //63 - Huge brow mushroom
+ m_blockFaces.put(Material.RED_MUSHROOM_BLOCK, new Shroom(m_tex, 2)); //64 - Huge red mushroom
}
@Override
@@ -67,16 +67,6 @@ public IDrawableElement getBlock(String name) {
}
int materialId = blockMaterial.getId();
- return getBlock(materialId);
- }
-
- @Override
- public IDrawableElement getBlock(int materialId) {
- if (m_blockFaces.containsKey(materialId))
- {
- return m_blockFaces.get(materialId);
- }
-
- return null;
+ return m_blockFaces.get(blockMaterial);
}
}
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/drawing/filters/FilterManager.java b/MCPainter/src/main/java/org/primesoft/mcpainter/drawing/filters/FilterManager.java
index afd8b54..51e13f9 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/drawing/filters/FilterManager.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/drawing/filters/FilterManager.java
@@ -28,8 +28,8 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
-import org.primesoft.mcpainter.Configuration.ConfigProvider;
-import org.primesoft.mcpainter.Configuration.OperationType;
+import org.primesoft.mcpainter.configuration.ConfigProvider;
+import org.primesoft.mcpainter.configuration.OperationType;
import org.primesoft.mcpainter.drawing.IColorMap;
import org.primesoft.mcpainter.MCPainterMain;
import org.bukkit.ChatColor;
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/drawing/statue/BaseStatue.java b/MCPainter/src/main/java/org/primesoft/mcpainter/drawing/statue/BaseStatue.java
index a35b3e6..b64ca0a 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/drawing/statue/BaseStatue.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/drawing/statue/BaseStatue.java
@@ -24,7 +24,7 @@
package org.primesoft.mcpainter.drawing.statue;
import org.primesoft.mcpainter.blocksplacer.BlockLoger;
-import org.primesoft.mcpainter.Configuration.OperationType;
+import org.primesoft.mcpainter.configuration.OperationType;
import org.primesoft.mcpainter.drawing.Face;
import org.primesoft.mcpainter.drawing.IColorMap;
import org.primesoft.mcpainter.drawing.ImageHelper;
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/mapdrawer/MapHelper.java b/MCPainter/src/main/java/org/primesoft/mcpainter/mapdrawer/MapHelper.java
index 6de0ebf..4787d90 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/mapdrawer/MapHelper.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/mapdrawer/MapHelper.java
@@ -30,7 +30,7 @@
import java.util.HashMap;
import java.util.List;
import javax.imageio.ImageIO;
-import org.primesoft.mcpainter.Configuration.ConfigProvider;
+import org.primesoft.mcpainter.configuration.ConfigProvider;
import org.primesoft.mcpainter.MCPainterMain;
import org.primesoft.mcpainter.utils.ExceptionHelper;
import org.bukkit.Bukkit;
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/mcstats/Metrics.java b/MCPainter/src/main/java/org/primesoft/mcpainter/mcstats/Metrics.java
deleted file mode 100644
index 7e9feec..0000000
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/mcstats/Metrics.java
+++ /dev/null
@@ -1,625 +0,0 @@
-/*
- * Copyright 2011 Tyler Blair. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are
- * permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this list of
- * conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice, this list
- * of conditions and the following disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and documentation are those of the
- * authors and contributors and should not be interpreted as representing official policies,
- * either expressed or implied, of anybody else.
- */
-package org.primesoft.mcpainter.drawing;
-
-import org.bukkit.Bukkit;
-import org.bukkit.configuration.file.YamlConfiguration;
-import org.bukkit.configuration.InvalidConfigurationException;
-import org.bukkit.plugin.Plugin;
-import org.bukkit.plugin.PluginDescriptionFile;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.io.UnsupportedEncodingException;
-import java.net.Proxy;
-import java.net.URL;
-import java.net.URLConnection;
-import java.net.URLEncoder;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.Set;
-import java.util.UUID;
-import java.util.logging.Level;
-
-/**
- * The metrics class obtains data about a plugin and submits statistics
- * about it to the metrics backend.
Public methods provided by this
- * class:
- *
- * Graph createGraph(String name);
- * void addCustomData(Metrics.Plotter plotter);
- * void start();
- *
- */
-public class Metrics {
-
- /**
- * The current revision number
- */
- private final static int REVISION = 5;
- /**
- * The base url of the metrics domain
- */
- private static final String BASE_URL = "http://mcstats.org";
- /**
- * The url used to report a server's status
- */
- private static final String REPORT_URL = "/report/%s";
- /**
- * The separator to use for custom data. This MUST NOT change unless you are
- * hosting your own version of metrics and want to change it.
- */
- private static final String CUSTOM_DATA_SEPARATOR = "~~";
- /**
- * Interval of time to ping (in minutes)
- */
- private static final int PING_INTERVAL = 10;
- /**
- * The plugin this metrics submits for
- */
- private final Plugin plugin;
- /**
- * All of the custom graphs to submit to metrics
- */
- private final Set graphs = Collections.synchronizedSet(new HashSet());
- /**
- * The default graph, used for addCustomData when you don't want a specific
- * graph
- */
- private final Graph defaultGraph = new Graph("Default");
- /**
- * The plugin configuration file
- */
- private final YamlConfiguration configuration;
- /**
- * The plugin configuration file
- */
- private final File configurationFile;
- /**
- * Unique server id
- */
- private final String guid;
- /**
- * Lock for synchronization
- */
- private final Object optOutLock = new Object();
- /**
- * Id of the scheduled task
- */
- private volatile int taskId = -1;
-
- public Metrics(final Plugin plugin) throws IOException {
- if (plugin == null) {
- throw new IllegalArgumentException("Plugin cannot be null");
- }
-
- this.plugin = plugin;
-
- // load the config
- configurationFile = getConfigFile();
- configuration = YamlConfiguration.loadConfiguration(configurationFile);
-
- // add some defaults
- configuration.addDefault("opt-out", false);
- configuration.addDefault("guid", UUID.randomUUID().toString());
-
- // Do we need to create the file?
- if (configuration.get("guid", null) == null) {
- configuration.options().header("http://mcstats.org").copyDefaults(true);
- configuration.save(configurationFile);
- }
-
- // Load the guid then
- guid = configuration.getString("guid");
- }
-
- /**
- * Construct and create a Graph that can be used to separate specific
- * plotters to their own graphs on the metrics website. Plotters can be
- * added to the graph object returned.
- *
- * @param name The name of the graph
- * @return Graph object created. Will never return NULL under normal
- * circumstances unless bad parameters are given
- */
- public Graph createGraph(final String name) {
- if (name == null) {
- throw new IllegalArgumentException("Graph name cannot be null");
- }
-
- // Construct the graph object
- final Graph graph = new Graph(name);
-
- // Now we can add our graph
- graphs.add(graph);
-
- // and return back
- return graph;
- }
-
- /**
- * Add a Graph object to Metrics that represents data for the plugin that
- * should be sent to the backend
- *
- * @param graph The name of the graph
- */
- public void addGraph(final Graph graph) {
- if (graph == null) {
- throw new IllegalArgumentException("Graph cannot be null");
- }
-
- graphs.add(graph);
- }
-
- /**
- * Adds a custom data plotter to the default graph
- *
- * @param plotter The plotter to use to plot custom data
- */
- public void addCustomData(final Plotter plotter) {
- if (plotter == null) {
- throw new IllegalArgumentException("Plotter cannot be null");
- }
-
- // Add the plotter to the graph o/
- defaultGraph.addPlotter(plotter);
-
- // Ensure the default graph is included in the submitted graphs
- graphs.add(defaultGraph);
- }
-
- /**
- * Start measuring statistics. This will immediately create an async
- * repeating task as the plugin and send the initial data to the metrics
- * backend, and then after that it will post in increments of PING_INTERVAL
- * * 1200 ticks.
- *
- * @return True if statistics measuring is running, otherwise false.
- */
- public boolean start() {
- synchronized (optOutLock) {
- // Did we opt out?
- if (isOptOut()) {
- return false;
- }
-
- // Is metrics already running?
- if (taskId >= 0) {
- return true;
- }
-
- // Begin hitting the server with glorious data
- taskId = plugin.getServer().getScheduler().scheduleAsyncRepeatingTask(plugin, new Runnable() {
-
- private boolean firstPost = true;
-
- public void run() {
- try {
- // This has to be synchronized or it can collide with the disable method.
- synchronized (optOutLock) {
- // Disable Task, if it is running and the server owner decided to opt-out
- if (isOptOut() && taskId > 0) {
- plugin.getServer().getScheduler().cancelTask(taskId);
- taskId = -1;
- // Tell all plotters to stop gathering information.
- for (Graph graph : graphs) {
- graph.onOptOut();
- }
- }
- }
-
- // We use the inverse of firstPost because if it is the first time we are posting,
- // it is not a interval ping, so it evaluates to FALSE
- // Each time thereafter it will evaluate to TRUE, i.e PING!
- postPlugin(!firstPost);
-
- // After the first post we set firstPost to false
- // Each post thereafter will be a ping
- firstPost = false;
- } catch (IOException e) {
- Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage());
- }
- }
- }, 0, PING_INTERVAL * 1200);
-
- return true;
- }
- }
-
- /**
- * Has the server owner denied plugin metrics?
- *
- * @return true if metrics should be opted out of it
- */
- public boolean isOptOut() {
- synchronized (optOutLock) {
- try {
- // Reload the metrics file
- configuration.load(getConfigFile());
- } catch (IOException ex) {
- Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
- return true;
- } catch (InvalidConfigurationException ex) {
- Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
- return true;
- }
- return configuration.getBoolean("opt-out", false);
- }
- }
-
- /**
- * Enables metrics for the server by setting "opt-out" to false in the
- * config file and starting the metrics task.
- *
- * @throws IOException
- */
- public void enable() throws IOException {
- // This has to be synchronized or it can collide with the check in the task.
- synchronized (optOutLock) {
- // Check if the server owner has already set opt-out, if not, set it.
- if (isOptOut()) {
- configuration.set("opt-out", false);
- configuration.save(configurationFile);
- }
-
- // Enable Task, if it is not running
- if (taskId < 0) {
- start();
- }
- }
- }
-
- /**
- * Disables metrics for the server by setting "opt-out" to true in the
- * config file and canceling the metrics task.
- *
- * @throws IOException
- */
- public void disable() throws IOException {
- // This has to be synchronized or it can collide with the check in the task.
- synchronized (optOutLock) {
- // Check if the server owner has already set opt-out, if not, set it.
- if (!isOptOut()) {
- configuration.set("opt-out", true);
- configuration.save(configurationFile);
- }
-
- // Disable Task, if it is running
- if (taskId > 0) {
- this.plugin.getServer().getScheduler().cancelTask(taskId);
- taskId = -1;
- }
- }
- }
-
- /**
- * Gets the File object of the config file that should be used to store data
- * such as the GUID and opt-out status
- *
- * @return the File object for the config file
- */
- public File getConfigFile() {
- // I believe the easiest way to get the base folder (e.g craftbukkit set via -P) for plugins to use
- // is to abuse the plugin object we already have
- // plugin.getDataFolder() => base/plugins/PluginA/
- // pluginsFolder => base/plugins/
- // The base is not necessarily relative to the startup directory.
- File pluginsFolder = plugin.getDataFolder().getParentFile();
-
- // return => base/plugins/PluginMetrics/config.yml
- return new File(new File(pluginsFolder, "PluginMetrics"), "config.yml");
- }
-
- /**
- * Generic method that posts a plugin to the metrics website
- */
- private void postPlugin(final boolean isPing) throws IOException {
- // The plugin's description file containg all of the plugin data such as name, version, author, etc
- final PluginDescriptionFile description = plugin.getDescription();
-
- // Construct the post data
- final StringBuilder data = new StringBuilder();
- data.append(encode("guid")).append('=').append(encode(guid));
- encodeDataPair(data, "version", description.getVersion());
- encodeDataPair(data, "server", Bukkit.getVersion());
- encodeDataPair(data, "players", Integer.toString(Bukkit.getServer().getOnlinePlayers().size()));
- encodeDataPair(data, "revision", String.valueOf(REVISION));
-
- // If we're pinging, append it
- if (isPing) {
- encodeDataPair(data, "ping", "true");
- }
-
- // Acquire a lock on the graphs, which lets us make the assumption we also lock everything
- // inside of the graph (e.g plotters)
- synchronized (graphs) {
- final Iterator iter = graphs.iterator();
-
- while (iter.hasNext()) {
- final Graph graph = iter.next();
-
- for (Plotter plotter : graph.getPlotters()) {
- // The key name to send to the metrics server
- // The format is C-GRAPHNAME-PLOTTERNAME where separator - is defined at the top
- // Legacy (R4) submitters use the format Custom%s, or CustomPLOTTERNAME
- final String key = String.format("C%s%s%s%s", CUSTOM_DATA_SEPARATOR, graph.getName(), CUSTOM_DATA_SEPARATOR, plotter.getColumnName());
-
- // The value to send, which for the foreseeable future is just the string
- // value of plotter.getValue()
- final String value = Integer.toString(plotter.getValue());
-
- // Add it to the http post data :)
- encodeDataPair(data, key, value);
- }
- }
- }
-
- // Create the url
- URL url = new URL(BASE_URL + String.format(REPORT_URL, encode(plugin.getDescription().getName())));
-
- // Connect to the website
- URLConnection connection;
-
- // Mineshafter creates a socks proxy, so we can safely bypass it
- // It does not reroute POST requests so we need to go around it
- if (isMineshafterPresent()) {
- connection = url.openConnection(Proxy.NO_PROXY);
- } else {
- connection = url.openConnection();
- }
-
- connection.setDoOutput(true);
-
- // Write the data
- final OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
- writer.write(data.toString());
- writer.flush();
-
- // Now read the response
- final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
- final String response = reader.readLine();
-
- // close resources
- writer.close();
- reader.close();
-
- if (response == null || response.startsWith("ERR")) {
- throw new IOException(response); //Throw the exception
- } else {
- // Is this the first update this hour?
- if (response.contains("OK This is your first update this hour")) {
- synchronized (graphs) {
- final Iterator iter = graphs.iterator();
-
- while (iter.hasNext()) {
- final Graph graph = iter.next();
-
- for (Plotter plotter : graph.getPlotters()) {
- plotter.reset();
- }
- }
- }
- }
- }
- }
-
- /**
- * Check if mineshafter is present. If it is, we need to bypass it to send
- * POST requests
- *
- * @return true if mineshafter is installed on the server
- */
- private boolean isMineshafterPresent() {
- try {
- Class.forName("mineshafter.MineServer");
- return true;
- } catch (Exception e) {
- return false;
- }
- }
-
- /**
- * Encode a key/value data pair to be used in a HTTP post request. This
- * INCLUDES a & so the first key/value pair MUST be included manually,
- * e.g:
- *
- * StringBuffer data = new StringBuffer();
- * data.append(encode("guid")).append('=').append(encode(guid));
- * encodeDataPair(data, "version", description.getVersion());
- *
- *
- * @param buffer the stringbuilder to append the data pair onto
- * @param key the key value
- * @param value the value
- */
- private static void encodeDataPair(final StringBuilder buffer, final String key, final String value) throws UnsupportedEncodingException {
- buffer.append('&').append(encode(key)).append('=').append(encode(value));
- }
-
- /**
- * Encode text as UTF-8
- *
- * @param text the text to encode
- * @return the encoded text, as UTF-8
- */
- private static String encode(final String text) throws UnsupportedEncodingException {
- return URLEncoder.encode(text, "UTF-8");
- }
-
- /**
- * Represents a custom graph on the website
- */
- public static class Graph {
-
- /**
- * The graph's name, alphanumeric and spaces only :) If it does not
- * comply to the above when submitted, it is rejected
- */
- private final String name;
- /**
- * The set of plotters that are contained within this graph
- */
- private final Set plotters = new LinkedHashSet();
-
- private Graph(final String name) {
- this.name = name;
- }
-
- /**
- * Gets the graph's name
- *
- * @return the Graph's name
- */
- public String getName() {
- return name;
- }
-
- /**
- * Add a plotter to the graph, which will be used to plot entries
- *
- * @param plotter the plotter to add to the graph
- */
- public void addPlotter(final Plotter plotter) {
- plotters.add(plotter);
- }
-
- /**
- * Remove a plotter from the graph
- *
- * @param plotter the plotter to remove from the graph
- */
- public void removePlotter(final Plotter plotter) {
- plotters.remove(plotter);
- }
-
- /**
- * Gets an unmodifiable set of the plotter objects in the graph
- *
- * @return an unmodifiable {@link Set} of the plotter objects
- */
- public Set getPlotters() {
- return Collections.unmodifiableSet(plotters);
- }
-
- @Override
- public int hashCode() {
- return name.hashCode();
- }
-
- @Override
- public boolean equals(final Object object) {
- if (!(object instanceof Graph)) {
- return false;
- }
-
- final Graph graph = (Graph) object;
- return graph.name.equals(name);
- }
-
- /**
- * Called when the server owner decides to opt-out of Metrics while the
- * server is running.
- */
- protected void onOptOut() {
- }
- }
-
- /**
- * Interface used to collect custom data for a plugin
- */
- public static abstract class Plotter {
-
- /**
- * The plot's name
- */
- private final String name;
-
- /**
- * Construct a plotter with the default plot name
- */
- public Plotter() {
- this("Default");
- }
-
- /**
- * Construct a plotter with a specific plot name
- *
- * @param name the name of the plotter to use, which will show up on the
- * website
- */
- public Plotter(final String name) {
- this.name = name;
- }
-
- /**
- * Get the current value for the plotted point. Since this function
- * defers to an external function it may or may not return immediately
- * thus cannot be guaranteed to be thread friendly or safe. This
- * function can be called from any thread so care should be taken when
- * accessing resources that need to be synchronized.
- *
- * @return the current value for the point to be plotted.
- */
- public abstract int getValue();
-
- /**
- * Get the column name for the plotted point
- *
- * @return the plotted point's column name
- */
- public String getColumnName() {
- return name;
- }
-
- /**
- * Called after the website graphs have been updated
- */
- public void reset() {
- }
-
- @Override
- public int hashCode() {
- return getColumnName().hashCode();
- }
-
- @Override
- public boolean equals(final Object object) {
- if (!(object instanceof Plotter)) {
- return false;
- }
-
- final Plotter plotter = (Plotter) object;
- return plotter.name.equals(name) && plotter.getValue() == getValue();
- }
- }
-}
\ No newline at end of file
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/mcstats/MetricsLite.java b/MCPainter/src/main/java/org/primesoft/mcpainter/mcstats/MetricsLite.java
index dc8ca5e..d5b400f 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/mcstats/MetricsLite.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/mcstats/MetricsLite.java
@@ -1,15 +1,15 @@
/*
- * Copyright 2011 Tyler Blair. All rights reserved.
+ * Copyright 2011-2013 Tyler Blair. All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without modification, are
+ * Redistribution in source, use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
- * 1. Redistributions of source code must retain the above copyright notice, this list of
- * conditions and the following disclaimer.
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
*
- * 2. Redistributions in binary form must reproduce the above copyright notice, this list
- * of conditions and the following disclaimer in the documentation and/or other materials
- * provided with the distribution.
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
@@ -25,69 +25,91 @@
* authors and contributors and should not be interpreted as representing official policies,
* either expressed or implied, of anybody else.
*/
-package org.primesoft.mcpainter.drawing;
+package org.primesoft.mcpainter.mcstats;
import org.bukkit.Bukkit;
+import org.bukkit.Server;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
+import org.bukkit.scheduler.BukkitTask;
import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
+import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
+import java.util.Collection;
import java.util.UUID;
import java.util.logging.Level;
+import java.util.zip.GZIPOutputStream;
public class MetricsLite {
/**
* The current revision number
*/
- private final static int REVISION = 5;
+ private final static int REVISION = 7;
+
/**
* The base url of the metrics domain
*/
- private static final String BASE_URL = "http://mcstats.org";
+ private static final String BASE_URL = "http://report.mcstats.org";
+
/**
* The url used to report a server's status
*/
- private static final String REPORT_URL = "/report/%s";
+ private static final String REPORT_URL = "/plugin/%s";
+
/**
* Interval of time to ping (in minutes)
*/
- private final static int PING_INTERVAL = 10;
+ private final static int PING_INTERVAL = 15;
+
/**
* The plugin this metrics submits for
*/
private final Plugin plugin;
+
/**
* The plugin configuration file
*/
private final YamlConfiguration configuration;
+
/**
* The plugin configuration file
*/
private final File configurationFile;
+
/**
* Unique server id
*/
private final String guid;
+
+ /**
+ * Debug mode
+ */
+ private final boolean debug;
+
/**
* Lock for synchronization
*/
private final Object optOutLock = new Object();
+
/**
* Id of the scheduled task
*/
- private volatile int taskId = -1;
+ private volatile BukkitTask task = null;
public MetricsLite(Plugin plugin) throws IOException {
if (plugin == null) {
@@ -103,6 +125,7 @@ public MetricsLite(Plugin plugin) throws IOException {
// add some defaults
configuration.addDefault("opt-out", false);
configuration.addDefault("guid", UUID.randomUUID().toString());
+ configuration.addDefault("debug", false);
// Do we need to create the file?
if (configuration.get("guid", null) == null) {
@@ -112,6 +135,7 @@ public MetricsLite(Plugin plugin) throws IOException {
// Load the guid then
guid = configuration.getString("guid");
+ debug = configuration.getBoolean("debug", false);
}
/**
@@ -119,7 +143,7 @@ public MetricsLite(Plugin plugin) throws IOException {
* repeating task as the plugin and send the initial data to the metrics
* backend, and then after that it will post in increments of PING_INTERVAL
* * 1200 ticks.
- *
+ *
* @return True if statistics measuring is running, otherwise false.
*/
public boolean start() {
@@ -130,12 +154,12 @@ public boolean start() {
}
// Is metrics already running?
- if (taskId >= 0) {
+ if (task != null) {
return true;
}
// Begin hitting the server with glorious data
- taskId = plugin.getServer().getScheduler().scheduleAsyncRepeatingTask(plugin, new Runnable() {
+ task = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, new Runnable() {
private boolean firstPost = true;
@@ -144,9 +168,9 @@ public void run() {
// This has to be synchronized or it can collide with the disable method.
synchronized (optOutLock) {
// Disable Task, if it is running and the server owner decided to opt-out
- if (isOptOut() && taskId > 0) {
- plugin.getServer().getScheduler().cancelTask(taskId);
- taskId = -1;
+ if (isOptOut() && task != null) {
+ task.cancel();
+ task = null;
}
}
@@ -159,7 +183,9 @@ public void run() {
// Each post thereafter will be a ping
firstPost = false;
} catch (IOException e) {
- Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage());
+ if (debug) {
+ Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage());
+ }
}
}
}, 0, PING_INTERVAL * 1200);
@@ -170,7 +196,7 @@ public void run() {
/**
* Has the server owner denied plugin metrics?
- *
+ *
* @return true if metrics should be opted out of it
*/
public boolean isOptOut() {
@@ -179,10 +205,14 @@ public boolean isOptOut() {
// Reload the metrics file
configuration.load(getConfigFile());
} catch (IOException ex) {
- Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
+ if (debug) {
+ Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
+ }
return true;
} catch (InvalidConfigurationException ex) {
- Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
+ if (debug) {
+ Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
+ }
return true;
}
return configuration.getBoolean("opt-out", false);
@@ -192,8 +222,8 @@ public boolean isOptOut() {
/**
* Enables metrics for the server by setting "opt-out" to false in the
* config file and starting the metrics task.
- *
- * @throws IOException
+ *
+ * @throws java.io.IOException
*/
public void enable() throws IOException {
// This has to be synchronized or it can collide with the check in the task.
@@ -205,7 +235,7 @@ public void enable() throws IOException {
}
// Enable Task, if it is not running
- if (taskId < 0) {
+ if (task == null) {
start();
}
}
@@ -214,8 +244,8 @@ public void enable() throws IOException {
/**
* Disables metrics for the server by setting "opt-out" to true in the
* config file and canceling the metrics task.
- *
- * @throws IOException
+ *
+ * @throws java.io.IOException
*/
public void disable() throws IOException {
// This has to be synchronized or it can collide with the check in the task.
@@ -227,9 +257,9 @@ public void disable() throws IOException {
}
// Disable Task, if it is running
- if (taskId > 0) {
- this.plugin.getServer().getScheduler().cancelTask(taskId);
- taskId = -1;
+ if (task != null) {
+ task.cancel();
+ task = null;
}
}
}
@@ -237,7 +267,7 @@ public void disable() throws IOException {
/**
* Gets the File object of the config file that should be used to store data
* such as the GUID and opt-out status
- *
+ *
* @return the File object for the config file
*/
public File getConfigFile() {
@@ -252,28 +282,84 @@ public File getConfigFile() {
return new File(new File(pluginsFolder, "PluginMetrics"), "config.yml");
}
+ /**
+ * Gets the online player (backwards compatibility)
+ *
+ * @return online player amount
+ */
+ private int getOnlinePlayers() {
+ try {
+ Method onlinePlayerMethod = Server.class.getMethod("getOnlinePlayers");
+ if (onlinePlayerMethod.getReturnType().equals(Collection.class)) {
+ return ((Collection>) onlinePlayerMethod.invoke(Bukkit.getServer())).size();
+ } else {
+ return ((Player[]) onlinePlayerMethod.invoke(Bukkit.getServer())).length;
+ }
+ } catch (Exception ex) {
+ if (debug) {
+ Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
+ }
+ }
+
+ return 0;
+ }
+
/**
* Generic method that posts a plugin to the metrics website
*/
private void postPlugin(boolean isPing) throws IOException {
+ // Server software specific section
+ PluginDescriptionFile description = plugin.getDescription();
+ String pluginName = description.getName();
+ boolean onlineMode = Bukkit.getServer().getOnlineMode(); // TRUE if online mode is enabled
+ String pluginVersion = description.getVersion();
+ String serverVersion = Bukkit.getVersion();
+ int playersOnline = this.getOnlinePlayers();
+
+ // END server software specific section -- all code below does not use any code outside of this class / Java
+ // Construct the post data
+ StringBuilder json = new StringBuilder(1024);
+ json.append('{');
+
// The plugin's description file containg all of the plugin data such as name, version, author, etc
- final PluginDescriptionFile description = plugin.getDescription();
+ appendJSONPair(json, "guid", guid);
+ appendJSONPair(json, "plugin_version", pluginVersion);
+ appendJSONPair(json, "server_version", serverVersion);
+ appendJSONPair(json, "players_online", Integer.toString(playersOnline));
+
+ // New data as of R6
+ String osname = System.getProperty("os.name");
+ String osarch = System.getProperty("os.arch");
+ String osversion = System.getProperty("os.version");
+ String java_version = System.getProperty("java.version");
+ int coreCount = Runtime.getRuntime().availableProcessors();
+
+ // normalize os arch .. amd64 -> x86_64
+ if (osarch.equals("amd64")) {
+ osarch = "x86_64";
+ }
- // Construct the post data
- final StringBuilder data = new StringBuilder();
- data.append(encode("guid")).append('=').append(encode(guid));
- encodeDataPair(data, "version", description.getVersion());
- encodeDataPair(data, "server", Bukkit.getVersion());
- encodeDataPair(data, "players", Integer.toString(Bukkit.getServer().getOnlinePlayers().size()));
- encodeDataPair(data, "revision", String.valueOf(REVISION));
+ appendJSONPair(json, "osname", osname);
+ appendJSONPair(json, "osarch", osarch);
+ appendJSONPair(json, "osversion", osversion);
+ appendJSONPair(json, "cores", Integer.toString(coreCount));
+ appendJSONPair(json, "auth_mode", onlineMode ? "1" : "0");
+ appendJSONPair(json, "java_version", java_version);
// If we're pinging, append it
if (isPing) {
- encodeDataPair(data, "ping", "true");
+ appendJSONPair(json, "ping", "1");
}
+ // close json
+ json.append('}');
+
+ sendMetrics(pluginName, json);
+ }
+
+ private void sendMetrics(String pluginName, StringBuilder json) throws IOException, UnsupportedEncodingException, MalformedURLException {
// Create the url
- URL url = new URL(BASE_URL + String.format(REPORT_URL, encode(plugin.getDescription().getName())));
+ URL url = new URL(BASE_URL + String.format(REPORT_URL, urlEncode(pluginName)));
// Connect to the website
URLConnection connection;
@@ -286,31 +372,78 @@ private void postPlugin(boolean isPing) throws IOException {
connection = url.openConnection();
}
+ byte[] uncompressed = json.toString().getBytes();
+ byte[] compressed = gzip(json.toString());
+
+ // Headers
+ connection.addRequestProperty("User-Agent", "MCStats/" + REVISION);
+ connection.addRequestProperty("Content-Type", "application/json");
+ connection.addRequestProperty("Content-Encoding", "gzip");
+ connection.addRequestProperty("Content-Length", Integer.toString(compressed.length));
+ connection.addRequestProperty("Accept", "application/json");
+ connection.addRequestProperty("Connection", "close");
+
connection.setDoOutput(true);
+ if (debug) {
+ System.out.println("[Metrics] Prepared request for " + pluginName + " uncompressed=" + uncompressed.length + " compressed=" + compressed.length);
+ }
+
// Write the data
- final OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
- writer.write(data.toString());
- writer.flush();
+ OutputStream os = connection.getOutputStream();
+ os.write(compressed);
+ os.flush();
// Now read the response
final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
- final String response = reader.readLine();
+ String response = reader.readLine();
// close resources
- writer.close();
+ os.close();
reader.close();
- if (response == null || response.startsWith("ERR")) {
- throw new IOException(response); //Throw the exception
+ if (response == null || response.startsWith("ERR") || response.startsWith("7")) {
+ if (response == null) {
+ response = "null";
+ } else if (response.startsWith("7")) {
+ response = response.substring(response.startsWith("7,") ? 2 : 1);
+ }
+
+ throw new IOException(response);
}
- //if (response.startsWith("OK")) - We should get "OK" followed by an optional description if everything goes right
+ }
+
+ /**
+ * GZip compress a string of bytes
+ *
+ * @param input
+ * @return
+ */
+ public static byte[] gzip(String input) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ GZIPOutputStream gzos = null;
+
+ try {
+ gzos = new GZIPOutputStream(baos);
+ gzos.write(input.getBytes("UTF-8"));
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ if (gzos != null) {
+ try {
+ gzos.close();
+ } catch (IOException ignore) {
+ }
+ }
+ }
+
+ return baos.toByteArray();
}
/**
* Check if mineshafter is present. If it is, we need to bypass it to send
* POST requests
- *
+ *
* @return true if mineshafter is installed on the server
*/
private boolean isMineshafterPresent() {
@@ -323,30 +456,93 @@ private boolean isMineshafterPresent() {
}
/**
- * Encode a key/value data pair to be used in a HTTP post request. This
- * INCLUDES a & so the first key/value pair MUST be included manually,
- * e.g:
- *
- * StringBuffer data = new StringBuffer();
- * data.append(encode("guid")).append('=').append(encode(guid));
- * encodeDataPair(data, "version", description.getVersion());
- *
- *
- * @param buffer the stringbuilder to append the data pair onto
- * @param key the key value
- * @param value the value
+ * Appends a json encoded key/value pair to the given string builder.
+ *
+ * @param json
+ * @param key
+ * @param value
+ * @throws UnsupportedEncodingException
+ */
+ private static void appendJSONPair(StringBuilder json, String key, String value) throws UnsupportedEncodingException {
+ boolean isValueNumeric = false;
+
+ try {
+ if (value.equals("0") || !value.endsWith("0")) {
+ Double.parseDouble(value);
+ isValueNumeric = true;
+ }
+ } catch (NumberFormatException e) {
+ isValueNumeric = false;
+ }
+
+ if (json.charAt(json.length() - 1) != '{') {
+ json.append(',');
+ }
+
+ json.append(escapeJSON(key));
+ json.append(':');
+
+ if (isValueNumeric) {
+ json.append(value);
+ } else {
+ json.append(escapeJSON(value));
+ }
+ }
+
+ /**
+ * Escape a string to create a valid JSON string
+ *
+ * @param text
+ * @return
*/
- private static void encodeDataPair(final StringBuilder buffer, final String key, final String value) throws UnsupportedEncodingException {
- buffer.append('&').append(encode(key)).append('=').append(encode(value));
+ private static String escapeJSON(String text) {
+ StringBuilder builder = new StringBuilder();
+
+ builder.append('"');
+ for (int index = 0; index < text.length(); index++) {
+ char chr = text.charAt(index);
+
+ switch (chr) {
+ case '"':
+ case '\\':
+ builder.append('\\');
+ builder.append(chr);
+ break;
+ case '\b':
+ builder.append("\\b");
+ break;
+ case '\t':
+ builder.append("\\t");
+ break;
+ case '\n':
+ builder.append("\\n");
+ break;
+ case '\r':
+ builder.append("\\r");
+ break;
+ default:
+ if (chr < ' ') {
+ String t = "000" + Integer.toHexString(chr);
+ builder.append("\\u" + t.substring(t.length() - 4));
+ } else {
+ builder.append(chr);
+ }
+ break;
+ }
+ }
+ builder.append('"');
+
+ return builder.toString();
}
/**
* Encode text as UTF-8
- *
+ *
* @param text the text to encode
* @return the encoded text, as UTF-8
*/
- private static String encode(final String text) throws UnsupportedEncodingException {
+ private static String urlEncode(final String text) throws UnsupportedEncodingException {
return URLEncoder.encode(text, "UTF-8");
}
-}
\ No newline at end of file
+
+}
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/mods/ModBlockProvider.java b/MCPainter/src/main/java/org/primesoft/mcpainter/mods/ModBlockProvider.java
index 3e423f9..d964b86 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/mods/ModBlockProvider.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/mods/ModBlockProvider.java
@@ -40,7 +40,6 @@
*/
public class ModBlockProvider implements IBlockProvider {
- private final HashMap m_idBlocks;
private final HashMap m_nameBlocks;
private final int m_cnt;
@@ -52,12 +51,10 @@ public static ModBlockProvider load(TextureManager texture,
private ModBlockProvider(TextureManager texture,
ConfigurationSection blocksSection) {
- HashMap> definedBlocks = new HashMap>();
- HashMap> definedBlocksId = new HashMap>();
- m_cnt = loadBlocks(blocksSection, texture, definedBlocks, definedBlocksId);
+ HashMap> definedBlocks = new HashMap<>();
+ m_cnt = loadBlocks(blocksSection, texture, definedBlocks);
m_nameBlocks = aggregateBlocksName(definedBlocks);
- m_idBlocks = aggregateBlocksId(definedBlocksId);
}
/**
@@ -66,12 +63,10 @@ private ModBlockProvider(TextureManager texture,
* @param blocksSection
* @param texture
* @param definedBlocks
- * @param definedBlocksId
* @return
*/
private int loadBlocks(ConfigurationSection blocksSection, TextureManager texture,
- HashMap> definedBlocks,
- HashMap> definedBlocksId) {
+ HashMap> definedBlocks) {
Set sections = blocksSection.getKeys(false);
int cnt = 0;
for (String sName : sections) {
@@ -82,7 +77,6 @@ private int loadBlocks(ConfigurationSection blocksSection, TextureManager textur
String name = blockDefinition.getString("Name", "").toUpperCase();
String type = blockDefinition.getString("Type", "").toUpperCase();
- int id = blockDefinition.getInt("Id", -1);
int[] data = getData(blockDefinition);
int[] flags = BlockHelper.parseIntListEntry(blockDefinition.getIntegerList("Flags"));
if (flags != null && flags.length > 0) {
@@ -91,8 +85,8 @@ private int loadBlocks(ConfigurationSection blocksSection, TextureManager textur
ConfigurationSection instruction = blockDefinition.getConfigurationSection("Instruction");
- if (name.length() == 0 && id == -1) {
- MCPainterMain.log(sName + ": block Id or name is required.");
+ if (name.length() == 0) {
+ MCPainterMain.log(sName + ": block name is required.");
continue;
}
if (instruction == null) {
@@ -143,7 +137,7 @@ private int loadBlocks(ConfigurationSection blocksSection, TextureManager textur
MCPainterMain.log(sName + ": Warning multi block detected, ignoring data value");
data = null;
}
- boolean added = addBlock(name, definedBlocks, id, definedBlocksId, data, sName, block);
+ boolean added = addBlock(name, definedBlocks, data, sName, block);
if (added) {
cnt++;
}
@@ -152,7 +146,6 @@ private int loadBlocks(ConfigurationSection blocksSection, TextureManager textur
}
private boolean addBlock(String name, HashMap> definedBlocks,
- int id, HashMap> definedBlocksId,
int[] data, String sectionName, IDrawableElement block) {
if (data == null) {
data = new int[]{0};
@@ -160,7 +153,7 @@ private boolean addBlock(String name, HashMap());
+ definedBlocks.put(name, new HashMap<>());
}
HashMap blockEntries = definedBlocks.get(name);
@@ -176,32 +169,6 @@ private boolean addBlock(String name, HashMap());
- }
-
- HashMap blockEntries = definedBlocksId.get(id);
- for (int i : data) {
- if (i > Short.MAX_VALUE || i < 0) {
- MCPainterMain.log(sectionName + ": invalid block data " + i + ".");
- continue;
- }
- if (blockEntries.containsKey((short) i)) {
- MCPainterMain.log(sectionName + ": duplicate block data value " + i + ".");
- } else {
- blockEntries.put((short) i, block);
- added = true;
- }
- }
- }
}
return added;
}
@@ -222,35 +189,6 @@ public IDrawableElement getBlock(String name) {
return m_nameBlocks.get(name);
}
- Material mat = Material.getMaterial(name);
- if (mat == null) {
- return null;
- }
-
- int id = mat.getId();
- if (m_idBlocks.containsKey(id)) {
- return m_idBlocks.get(id);
- }
-
- return null;
- }
-
- @Override
- public IDrawableElement getBlock(int materialId) {
- if (m_idBlocks.containsKey(materialId)) {
- return m_idBlocks.get(materialId);
- }
-
- Material mat = Material.getMaterial(materialId);
- if (mat == null) {
- return null;
- }
-
- String name = mat.toString();
- if (m_nameBlocks.containsKey(name)) {
- return m_nameBlocks.get(name);
- }
-
return null;
}
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/palettes/Palette.java b/MCPainter/src/main/java/org/primesoft/mcpainter/palettes/Palette.java
index daffad6..210c1be 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/palettes/Palette.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/palettes/Palette.java
@@ -26,7 +26,7 @@
import java.io.File;
import java.util.ArrayList;
import java.util.List;
-import org.primesoft.mcpainter.Configuration.BlockEntry;
+import org.primesoft.mcpainter.configuration.BlockEntry;
import org.primesoft.mcpainter.drawing.ColorMap;
import org.primesoft.mcpainter.drawing.IColorMap;
import org.primesoft.mcpainter.MCPainterMain;
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/texture/TextureDescription.java b/MCPainter/src/main/java/org/primesoft/mcpainter/texture/TextureDescription.java
index 907668b..8a57781 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/texture/TextureDescription.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/texture/TextureDescription.java
@@ -34,40 +34,35 @@ public class TextureDescription {
private int m_column;
private int m_row;
- public static TextureDescription parse(String s) {
+ public static TextureDescription parse(String s) {
if (s == null) {
return null;
}
String[] parts = s.split(":");
- if (parts.length < 2)
- {
+ if (parts.length < 2) {
return null;
}
-
+
String tPack = parts[0];
String file = parts[1];
int column = -1;
int row = -1;
-
- if (parts.length >= 3 && parts[2] != null)
- {
+
+ if (parts.length >= 3 && parts[2] != null) {
try {
column = Integer.parseInt(parts[2]);
- } catch (NumberFormatException ex)
- {
-
+ } catch (NumberFormatException ex) {
+
}
}
- if (parts.length >= 4 && parts[3] != null)
- {
+ if (parts.length >= 4 && parts[3] != null) {
try {
row = Integer.parseInt(parts[3]);
- } catch (NumberFormatException ex)
- {
-
+ } catch (NumberFormatException ex) {
+
}
}
-
+
return new TextureDescription(tPack, file, column, row);
}
@@ -104,11 +99,13 @@ public String toString() {
sb.append(m_texturePack);
sb.append(":");
sb.append(m_file);
- sb.append(":");
- sb.append(m_column);
- sb.append("x");
- sb.append(m_row);
+ if (m_column >= 0 || m_row >= 0) {
+ sb.append(":");
+ sb.append(m_column);
+ sb.append("x");
+ sb.append(m_row);
+ }
return sb.toString();
- }
+ }
}
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/texture/TextureManager.java b/MCPainter/src/main/java/org/primesoft/mcpainter/texture/TextureManager.java
index ec8594e..dbe3c3b 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/texture/TextureManager.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/texture/TextureManager.java
@@ -27,7 +27,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import org.primesoft.mcpainter.Configuration.ConfigProvider;
+import org.primesoft.mcpainter.configuration.ConfigProvider;
import org.primesoft.mcpainter.drawing.RawImage;
/**
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/texture/TexturePack.java b/MCPainter/src/main/java/org/primesoft/mcpainter/texture/TexturePack.java
index 56c6ddd..dd20df8 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/texture/TexturePack.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/texture/TexturePack.java
@@ -32,7 +32,7 @@
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import javax.imageio.ImageIO;
-import org.primesoft.mcpainter.Configuration.ConfigProvider;
+import org.primesoft.mcpainter.configuration.ConfigProvider;
import org.primesoft.mcpainter.drawing.RawImage;
/**
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/texture/TextureProvider.java b/MCPainter/src/main/java/org/primesoft/mcpainter/texture/TextureProvider.java
index 83c1962..e39c15d 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/texture/TextureProvider.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/texture/TextureProvider.java
@@ -25,7 +25,6 @@
import java.io.File;
import org.primesoft.mcpainter.drawing.RawImage;
-import org.primesoft.mcpainter.MCPainterMain;
/**
*
@@ -118,7 +117,7 @@ protected TextureEntry getTexture(String[] files, String name, int[] columns, in
if (img == null) {
img = m_specified.getFile(files[i]);
}
- if (img == null) {
+ if (img == null) {
return null;
}
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/texture/VanillaTextureProvider.java b/MCPainter/src/main/java/org/primesoft/mcpainter/texture/VanillaTextureProvider.java
index 85a685a..fcc63a6 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/texture/VanillaTextureProvider.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/texture/VanillaTextureProvider.java
@@ -84,26 +84,26 @@ public TextureEntry getTexture(String fileName, String name) {
}
public TextureEntry getAnvil() {
- final String[] files = new String[]{"blocks/anvil_base.png", "blocks/anvil_top_damaged_0.png", "blocks/anvil_top_damaged_1.png", "blocks/anvil_top_damaged_2.png"};
+ final String[] files = new String[]{"block/anvil.png", "block/anvil_top.png", "block/chipped_anvil_top.png", "block/damaged_anvil_top.png"};
return getTexture(files, "Anvil");
}
public TextureEntry getBeacon() {
- return getTexture("blocks/beacon.png", "Beacon");
+ return getTexture("block/beacon.png", "Beacon");
}
public TextureEntry getBrewingStand() {
- final String[] files = new String[]{"blocks/brewing_stand.png", "blocks/brewing_stand_base.png"};
+ final String[] files = new String[]{"block/brewing_stand.png", "block/brewing_stand_base.png"};
return getTexture(files, "BrewingStand");
}
public TextureEntry getMushroomBlock() {
- final String[] files = new String[]{"blocks/mushroom_block_skin_stem.png", "blocks/mushroom_block_inside.png", "blocks/mushroom_block_skin_red.png", "blocks/mushroom_block_skin_brown.png"};
+ final String[] files = new String[]{"block/mushroom_stem.png", "block/mushroom_block_inside.png", "block/red_mushroom_block.png", "block/brown_mushroom_block.png"};
return getTexture(files, "MushroomBlock");
}
public TextureEntry getPiston() {
- final String[] files = new String[]{"blocks/piston_side.png", "blocks/piston_bottom.png", "blocks/piston_top_normal.png", "blocks/piston_top_sticky.png", "blocks/piston_inner.png"};
+ final String[] files = new String[]{"block/piston_side.png", "block/piston_bottom.png", "block/piston_top.png", "block/piston_top_sticky.png", "block/piston_inner.png"};
return getTexture(files, "Piston");
}
}
\ No newline at end of file
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/utils/BaseBlock.java b/MCPainter/src/main/java/org/primesoft/mcpainter/utils/BaseBlock.java
index da31409..ac0c28f 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/utils/BaseBlock.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/utils/BaseBlock.java
@@ -23,36 +23,32 @@
*/
package org.primesoft.mcpainter.utils;
+import org.bukkit.Bukkit;
import org.bukkit.Material;
+import org.bukkit.block.data.BlockData;
/**
*
* @author SBPrime
*/
public class BaseBlock {
-
- private final Material m_material;
- private final int m_data;
+ public static final BaseBlock AIR = new BaseBlock(Material.AIR);
- public int getData(){
- return m_data;
- }
+ public final BlockData Data;
- public int getType() {
- return m_material.getId();
+ public BaseBlock(Material material, String data) {
+ Data = Bukkit.getServer().createBlockData(material, data);
}
- public Material getMaterial() {
- return m_material;
+ public BaseBlock(Material material) {
+ Data = Bukkit.getServer().createBlockData(material);
}
- public BaseBlock(Material material, int data) {
- m_material = material;
- m_data = data;
+ public BaseBlock(String data) {
+ Data = Bukkit.getServer().createBlockData(data);
}
-
- public BaseBlock(Material material) {
- m_material = material;
- m_data = 0;
+
+ public BaseBlock(BlockData data) {
+ Data = data.clone();
}
}
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/utils/Orientation.java b/MCPainter/src/main/java/org/primesoft/mcpainter/utils/Orientation.java
index 4a873e5..a92512c 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/utils/Orientation.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/utils/Orientation.java
@@ -23,7 +23,7 @@
*/
package org.primesoft.mcpainter.utils;
-import org.primesoft.mcpainter.Configuration.ConfigProvider;
+import org.primesoft.mcpainter.configuration.ConfigProvider;
/**
*
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/utils/Vector.java b/MCPainter/src/main/java/org/primesoft/mcpainter/utils/Vector.java
index 0a6cc07..2e79a9c 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/utils/Vector.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/utils/Vector.java
@@ -94,4 +94,23 @@ public int getBlockZ() {
public Vector subtract(Vector v) {
return new Vector(m_x - v.m_x, m_y - v.m_y, m_z - v.m_z);
}
+
+ public static Vector parse(String s) {
+ if (s == null) {
+ return null;
+ }
+
+ String[] parts = s.split(",");
+ if (parts.length != 3) {
+ return null;
+ }
+
+ try {
+ return new Vector(Double.parseDouble(parts[0]),
+ Double.parseDouble(parts[1]),
+ Double.parseDouble(parts[2]));
+ } catch (NumberFormatException ex) {
+ return null;
+ }
+ }
}
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/voxelyzer/VoxelCanvas.java b/MCPainter/src/main/java/org/primesoft/mcpainter/voxelyzer/VoxelCanvas.java
index 6012a1d..fa213be 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/voxelyzer/VoxelCanvas.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/voxelyzer/VoxelCanvas.java
@@ -25,7 +25,7 @@
import java.awt.Color;
import org.primesoft.mcpainter.blocksplacer.BlockLoger;
-import org.primesoft.mcpainter.Configuration.OperationType;
+import org.primesoft.mcpainter.configuration.OperationType;
import org.primesoft.mcpainter.drawing.IColorMap;
import org.primesoft.mcpainter.drawing.ImageHelper;
import org.primesoft.mcpainter.drawing.RawImage;
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/blocksplacer/ChangeMessage.java b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/BaseEditSession.java
similarity index 63%
rename from MCPainter/src/main/java/org/primesoft/mcpainter/blocksplacer/ChangeMessage.java
rename to MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/BaseEditSession.java
index 6c89d67..1a3a9e1 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/blocksplacer/ChangeMessage.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/BaseEditSession.java
@@ -1,7 +1,7 @@
/*
* The MIT License
*
- * Copyright 2015 SBPrime.
+ * Copyright 2018 SBPrime.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,34 +21,30 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-package org.primesoft.mcpainter.blocksplacer;
+package org.primesoft.mcpainter.worldEdit;
-import com.sk89q.worldedit.WorldEditException;
-import com.sk89q.worldedit.history.UndoContext;
-import com.sk89q.worldedit.history.change.Change;
-import org.primesoft.mcpainter.MCPainterMain;
+import org.bukkit.World;
import org.bukkit.entity.Player;
+import org.primesoft.mcpainter.BlocksHubIntegration;
+import org.primesoft.mcpainter.utils.BaseBlock;
+import org.primesoft.mcpainter.utils.Vector;
/**
*
* @author SBPrime
*/
-public class ChangeMessage implements Change {
+abstract class BaseEditSession implements IEditSession {
private final Player m_player;
- private final String m_msg;
+ private final BlocksHubIntegration m_bh;
+ protected final World m_world;
- public ChangeMessage(Player player, String msg) {
- m_player = player;
- m_msg = msg;
+ protected BaseEditSession(ILocalPlayer p, BlocksHubIntegration bh) {
+ m_bh = bh;
+ m_world = p.getWorld();
+ m_player = p.getPlayer();
}
-
- @Override
- public void undo(UndoContext uc) throws WorldEditException {
- }
-
- @Override
- public void redo(UndoContext uc) throws WorldEditException {
- MCPainterMain.say(m_player, m_msg);
+ protected void logBlock(Vector location, BaseBlock oldBlock, BaseBlock newBlock) {
+ m_bh.logBlock(m_player, m_world, location, oldBlock, newBlock);
}
}
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/WorldEditCuboidSelection.java b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/CuboidSelection.java
similarity index 63%
rename from MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/WorldEditCuboidSelection.java
rename to MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/CuboidSelection.java
index 86e5471..82c6ad1 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/WorldEditCuboidSelection.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/CuboidSelection.java
@@ -21,45 +21,45 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+
package org.primesoft.mcpainter.worldEdit;
-import com.sk89q.worldedit.bukkit.selections.CuboidSelection;
import org.bukkit.Location;
+import org.bukkit.World;
+import org.primesoft.mcpainter.utils.Vector;
/**
*
* @author SBPrime
*/
-public class WorldEditCuboidSelection implements ICuboidSelection {
-
- private final CuboidSelection m_selection;
+public final class CuboidSelection {
- public WorldEditCuboidSelection(CuboidSelection cSelection) {
- m_selection = cSelection;
+ private final Vector m_pointMin;
+ private final Vector m_pointMax;
+ private final World m_world;
+
+ public CuboidSelection(Location from, Location to) {
+ m_pointMin = new Vector(from);
+ m_pointMax = new Vector(to);
+ m_world = from.getWorld();
}
-
- @Override
- public Location getMinimumPoint() {
- return m_selection.getMinimumPoint();
- }
-
- @Override
- public Location getMaximumPoint() {
- return m_selection.getMaximumPoint();
+
+ public CuboidSelection(World w, Vector from, Vector to) {
+ m_pointMin = from;
+ m_pointMax = to;
+ m_world = w;
}
- @Override
- public int getLength() {
- return m_selection.getLength();
+ public Vector getMinimumPoint() {
+ return m_pointMin;
}
- @Override
- public int getWidth() {
- return m_selection.getWidth();
+ public Vector getMaximumPoint() {
+ return m_pointMax;
}
- @Override
- public int getHeight() {
- return m_selection.getHeight();
+ public World getWorld() {
+ return m_world;
}
+
}
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/ICuboidSelection.java b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/ICuboidSelection.java
deleted file mode 100644
index 93b93f1..0000000
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/ICuboidSelection.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * The MIT License
- *
- * Copyright 2014 SBPrime.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-package org.primesoft.mcpainter.worldEdit;
-
-import org.bukkit.Location;
-
-/**
- *
- * @author SBPrime
- */
-public interface ICuboidSelection {
-
- public Location getMinimumPoint();
-
- public Location getMaximumPoint();
-
- public int getLength();
-
- public int getWidth();
-
- public int getHeight();
-
-}
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/IEditSession.java b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/IEditSession.java
index 632baf1..40ad9e1 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/IEditSession.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/IEditSession.java
@@ -24,8 +24,10 @@
package org.primesoft.mcpainter.worldEdit;
+import java.util.List;
import org.primesoft.mcpainter.utils.BaseBlock;
import org.primesoft.mcpainter.utils.Vector;
+import org.primesoft.mcpainter.blocksplacer.IChange;
/**
*
@@ -36,5 +38,8 @@ public interface IEditSession {
public BaseBlock getBlock(Vector location);
public void setBlock(Vector location, BaseBlock block) throws MaxChangedBlocksException;
+
+ public void doCustom(IChange command) throws MaxChangedBlocksException;
+ public List getChangeSet();
}
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/ILocalPlayer.java b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/ILocalPlayer.java
index d5afb23..e1a45a4 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/ILocalPlayer.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/ILocalPlayer.java
@@ -24,6 +24,8 @@
package org.primesoft.mcpainter.worldEdit;
+import org.bukkit.World;
+import org.bukkit.entity.Player;
import org.primesoft.mcpainter.utils.Vector;
/**
@@ -37,5 +39,8 @@ public interface ILocalPlayer {
public double getYaw();
public double getPitch();
-
+
+ public World getWorld();
+
+ public Player getPlayer();
}
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/IWorldEdit.java b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/IWorldEdit.java
index 74ef626..a7223bc 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/IWorldEdit.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/IWorldEdit.java
@@ -37,6 +37,7 @@ public interface IWorldEdit {
public ILocalPlayer wrapPlayer(Player player);
- public ICuboidSelection getSelection(Player player);
-
+ public CuboidSelection getSelection(Player player);
+
+ public void undo(Player player);
}
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/StubEditEditSession.java b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/StubEditEditSession.java
index cd000b3..359dd59 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/StubEditEditSession.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/StubEditEditSession.java
@@ -23,23 +23,25 @@
*/
package org.primesoft.mcpainter.worldEdit;
+import java.util.ArrayList;
+import java.util.List;
import org.primesoft.mcpainter.utils.BaseBlock;
import org.primesoft.mcpainter.utils.Vector;
import org.bukkit.Chunk;
import org.bukkit.Location;
-import org.bukkit.World;
import org.bukkit.block.Block;
+import org.primesoft.mcpainter.BlocksHubIntegration;
+import org.primesoft.mcpainter.blocksplacer.IChange;
/**
*
* @author SBPrime
*/
-class StubEditEditSession implements IEditSession {
-
- private World m_world;
-
- public StubEditEditSession(StubLocalPlayer stubLocalPlayer) {
- m_world = stubLocalPlayer.getWorld();
+class StubEditEditSession extends BaseEditSession {
+ private final List m_changeSet= new ArrayList<>();
+
+ public StubEditEditSession(ILocalPlayer localPlayer, BlocksHubIntegration bh) {
+ super(localPlayer, bh);
}
@Override
@@ -50,8 +52,8 @@ public BaseBlock getBlock(Vector location) {
chunk.load();
}
Block b = l.getBlock();
-
- return new BaseBlock(b.getType(), b.getData());
+
+ return new BaseBlock(b.getBlockData().clone());
}
@Override
@@ -61,9 +63,57 @@ public void setBlock(Vector location, BaseBlock block) throws MaxChangedBlocksEx
if (!chunk.isLoaded()) {
chunk.load();
}
+
Block b = l.getBlock();
- b.setType(block.getMaterial());
- b.setData((byte)block.getData());
+ BaseBlock oldBlock = new BaseBlock(b.getBlockData().clone());
+ b.setBlockData(block.Data);
+
+ IChange setBlockUndo = new UndoSetBlock(l, oldBlock);
+ logBlock(location, oldBlock, block);
+ m_changeSet.add(setBlockUndo);
+ }
+
+ @Override
+ public void doCustom(IChange command) throws MaxChangedBlocksException {
+ command.redo();
+
+ m_changeSet.add(command);
+ }
+
+ @Override
+ public List getChangeSet() {
+ return m_changeSet;
}
+ private static class UndoSetBlock implements IChange {
+
+ private final Location m_location;
+ private final BaseBlock m_block;
+
+ public UndoSetBlock(Location l, BaseBlock oldBlock) {
+ m_location = l;
+ m_block = oldBlock;
+ }
+
+ @Override
+ public Location getLocation() {
+ return m_location;
+ }
+
+ @Override
+ public void redo() {
+ throw new UnsupportedOperationException("Not supported, this is only for undo.");
+ }
+
+ @Override
+ public void undo() {
+ Chunk chunk = m_location.getChunk();
+ if (!chunk.isLoaded()) {
+ chunk.load();
+ }
+
+ Block b = m_location.getBlock();
+ b.setBlockData(m_block.Data);
+ }
+ }
}
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/StubLocalPlayer.java b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/StubLocalPlayer.java
index ae7df72..88c40f4 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/StubLocalPlayer.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/StubLocalPlayer.java
@@ -39,6 +39,11 @@ public StubLocalPlayer(Player player) {
m_player = player;
}
+ @Override
+ public Player getPlayer() {
+ return m_player;
+ }
+
@Override
public Vector getPosition() {
return new Vector(m_player.getLocation());
@@ -54,6 +59,7 @@ public double getPitch() {
return m_player.getLocation().getPitch();
}
+ @Override
public World getWorld() {
return m_player.getWorld();
}
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/StubLocalSession.java b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/StubLocalSession.java
index 1872fef..fa9909a 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/StubLocalSession.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/StubLocalSession.java
@@ -24,27 +24,37 @@
package org.primesoft.mcpainter.worldEdit;
-import org.bukkit.World;
import org.bukkit.entity.Player;
+import org.primesoft.mcpainter.BlocksHubIntegration;
/**
*
* @author SBPrime
*/
class StubLocalSession implements ILocalSession {
- public StubLocalSession(Player player) {
+
+ private final BlocksHubIntegration m_bh;
+ private final StubWrapper m_wrapper;
+ private final Player m_player;
+
+ public StubLocalSession(Player player, BlocksHubIntegration bh, StubWrapper wrapper) {
+ m_bh = bh;
+ m_wrapper = wrapper;
+ m_player = player;
}
@Override
- public void remember(IEditSession eSession) {
+ public void remember(IEditSession eSession) {
+ m_wrapper.setChangeset(m_player, eSession.getChangeSet());
}
@Override
public IEditSession createEditSession(ILocalPlayer localPlayer) {
if (!(localPlayer instanceof StubLocalPlayer)) {
throw new UnsupportedOperationException("Invalid argument.");
- }
- return new StubEditEditSession((StubLocalPlayer)localPlayer);
+ }
+
+ return new StubEditEditSession((StubLocalPlayer)localPlayer, m_bh);
}
}
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/StubWrapper.java b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/StubWrapper.java
index d0569a8..2f8f5ee 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/StubWrapper.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/StubWrapper.java
@@ -21,16 +21,42 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-
package org.primesoft.mcpainter.worldEdit;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.primesoft.mcpainter.BlocksHubIntegration;
+import org.primesoft.mcpainter.blocksplacer.BlockLoger;
+import org.primesoft.mcpainter.blocksplacer.BlockLogerEntry;
+import org.primesoft.mcpainter.blocksplacer.BlockPlacer;
+import org.primesoft.mcpainter.blocksplacer.IChange;
/**
*
* @author SBPrime
*/
-public class StubWrapper implements IWorldEdit {
+class StubWrapper implements IWorldEdit, Listener {
+
+ private static class Entry {
+
+ public List ChangeSet;
+ }
+
+ private final BlocksHubIntegration m_bh;
+ private final BlockPlacer m_bp;
+ private final ConcurrentMap m_changeSets = new ConcurrentHashMap<>();
+
+ public StubWrapper(BlocksHubIntegration bh, BlockPlacer bp) {
+ m_bh = bh;
+ m_bp = bp;
+ }
@Override
public boolean isRealWorldEdit() {
@@ -39,7 +65,7 @@ public boolean isRealWorldEdit() {
@Override
public ILocalSession getSession(Player player) {
- return new StubLocalSession(player);
+ return new StubLocalSession(player, m_bh, this);
}
@Override
@@ -48,7 +74,65 @@ public ILocalPlayer wrapPlayer(Player player) {
}
@Override
- public ICuboidSelection getSelection(Player player) {
+ public CuboidSelection getSelection(Player player) {
return null;
}
+
+ void setChangeset(Player player, final List changeSet) {
+ m_changeSets.computeIfPresent(player.getUniqueId(), (uuid, entry) -> {
+ entry.ChangeSet = changeSet;
+ return entry;
+ });
+ }
+
+ @EventHandler
+ public void onPlayerQuit(PlayerQuitEvent e) {
+ m_changeSets.remove(e.getPlayer().getUniqueId());
+ }
+
+ @EventHandler
+ public void onPlayerJoin(PlayerJoinEvent e) {
+ m_changeSets.put(e.getPlayer().getUniqueId(), new Entry());
+ }
+
+ @Override
+ public void undo(Player player) {
+ m_changeSets.computeIfPresent(player.getUniqueId(), (uuid, entry) -> {
+ List changes = entry.ChangeSet;
+ entry.ChangeSet = null;
+
+ if (changes == null) {
+ return entry;
+ }
+
+ BlockLogerEntry[] entries = new BlockLogerEntry[changes.size()];
+ int idx = 0;
+ for (IChange ch : changes) {
+ entries[idx] = new UndoEntry(ch);
+ idx++;
+ }
+ m_bp.addTasks(entries, player);
+ return entry;
+ });
+ }
+
+ private static class UndoEntry extends BlockLogerEntry {
+
+ private final IChange m_change;
+
+ public UndoEntry(IChange ch) {
+ super(null);
+ m_change = ch;
+ }
+
+ @Override
+ public boolean canRemove() {
+ return true;
+ }
+
+ @Override
+ public void execute() {
+ m_change.undo();
+ }
+ }
}
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/WorldEditEditSession.java b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/WorldEditEditSession.java
index 6fa1bf9..4ff4878 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/WorldEditEditSession.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/WorldEditEditSession.java
@@ -24,6 +24,13 @@
package org.primesoft.mcpainter.worldEdit;
import com.sk89q.worldedit.EditSession;
+import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.history.UndoContext;
+import com.sk89q.worldedit.history.change.Change;
+import com.sk89q.worldedit.history.changeset.ChangeSet;
+import java.util.List;
+import org.primesoft.mcpainter.BlocksHubIntegration;
+import org.primesoft.mcpainter.blocksplacer.IChange;
import org.primesoft.mcpainter.utils.BaseBlock;
import org.primesoft.mcpainter.utils.Vector;
@@ -31,11 +38,30 @@
*
* @author SBPrime
*/
-public class WorldEditEditSession implements IEditSession {
+class WorldEditEditSession extends BaseEditSession {
+ private static class ChangeWrapper implements Change {
+
+ private final IChange m_change;
+
+ public ChangeWrapper(IChange c) {
+ m_change = c;
+ }
+
+ @Override
+ public void undo(UndoContext uc) throws WorldEditException {
+ m_change.redo();
+ }
+
+ @Override
+ public void redo(UndoContext uc) throws WorldEditException {
+ m_change.undo();
+ }
+ }
private final EditSession m_editSession;
- public WorldEditEditSession(EditSession editSession) {
+ public WorldEditEditSession(ILocalPlayer p, EditSession editSession, BlocksHubIntegration bh) {
+ super(p, bh);
m_editSession = editSession;
}
@@ -45,20 +71,33 @@ public EditSession getEditSession() {
@Override
public BaseBlock getBlock(Vector location) {
- com.sk89q.worldedit.Vector v = WorldEditWrapper.convert(location);
- com.sk89q.worldedit.blocks.BaseBlock block = m_editSession.getBlock(v);
-
- return WorldEditWrapper.convert(block);
+ return WorldEditWrapper.convert(m_editSession.getBlock(WorldEditWrapper.convert(location)));
}
@Override
public void setBlock(Vector location, BaseBlock block) throws MaxChangedBlocksException {
- com.sk89q.worldedit.blocks.BaseBlock weBlock = WorldEditWrapper.convert(block);
com.sk89q.worldedit.Vector weLocaton = WorldEditWrapper.convert(location);
+ BaseBlock oldBlock = WorldEditWrapper.convert(m_editSession.getBlock(weLocaton));
+ com.sk89q.worldedit.world.block.BlockState weBlock = WorldEditWrapper.convert(block);
try {
m_editSession.setBlock(weLocaton, weBlock);
} catch (com.sk89q.worldedit.MaxChangedBlocksException ex) {
throw new MaxChangedBlocksException();
}
+
+ logBlock(location, oldBlock, block);
+ }
+
+ @Override
+ public void doCustom(IChange command) throws MaxChangedBlocksException {
+ ChangeSet cs = m_editSession.getChangeSet();
+ command.redo();
+ cs.add(new ChangeWrapper(command));
+ }
+
+ @Override
+ public List getChangeSet() {
+ return null;
}
-}
\ No newline at end of file
+
+}
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/WorldEditFactory.java b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/WorldEditFactory.java
index 76f78ba..26b939a 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/WorldEditFactory.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/WorldEditFactory.java
@@ -48,15 +48,18 @@ private static Plugin getWorldEdit(JavaPlugin plugin) {
}
}
- public static IWorldEdit getWorldEditWrapper(JavaPlugin plugin) {
+ public static IWorldEdit getWorldEditWrapper(MCPainterMain plugin) {
Plugin wePlugin = getWorldEdit(plugin);
if (wePlugin != null) {
MCPainterMain.log("WorldEdit found - using the \"real thing\".");
- return new WorldEditWrapper(wePlugin);
+ return new WorldEditWrapper(wePlugin, plugin.getBlocksHub());
}
MCPainterMain.log("WorldEdit not found - using stub wrapper classes.");
- return new StubWrapper();
+
+ StubWrapper result = new StubWrapper(plugin.getBlocksHub(), plugin.getBlockPlacer());
+ plugin.getServer().getPluginManager().registerEvents(result, plugin);
+ return result;
}
}
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/WorldEditLocalPlayer.java b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/WorldEditLocalPlayer.java
index b5e1945..c05aca3 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/WorldEditLocalPlayer.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/WorldEditLocalPlayer.java
@@ -24,7 +24,8 @@
package org.primesoft.mcpainter.worldEdit;
-import com.sk89q.worldedit.LocalPlayer;
+import org.bukkit.World;
+import org.bukkit.entity.Player;
import org.primesoft.mcpainter.utils.Vector;
/**
@@ -32,28 +33,40 @@
* @author SBPrime
*/
public class WorldEditLocalPlayer implements ILocalPlayer {
- private final LocalPlayer m_localPlayer;
+ private final com.sk89q.worldedit.entity.Player m_localPlayer;
+ private final Player m_player;
- public WorldEditLocalPlayer(LocalPlayer localPlayer) {
+ public WorldEditLocalPlayer(com.sk89q.worldedit.entity.Player localPlayer, Player player) {
m_localPlayer = localPlayer;
+ m_player = player;
}
- public LocalPlayer getLocalPlayer(){
+ public com.sk89q.worldedit.entity.Player getLocalPlayer(){
return m_localPlayer;
}
@Override
public Vector getPosition() {
- return WorldEditWrapper.convert(m_localPlayer.getPosition());
+ return WorldEditWrapper.convert(m_localPlayer.getLocation().toVector());
}
@Override
public double getYaw() {
- return m_localPlayer.getYaw();
+ return m_localPlayer.getLocation().getYaw();
}
@Override
public double getPitch() {
- return m_localPlayer.getPitch();
+ return m_localPlayer.getLocation().getPitch();
+ }
+
+ @Override
+ public World getWorld() {
+ return m_player.getWorld();
+ }
+
+ @Override
+ public Player getPlayer() {
+ return m_player;
}
}
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/WorldEditLocalSession.java b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/WorldEditLocalSession.java
index 0c72952..9e15e61 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/WorldEditLocalSession.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/WorldEditLocalSession.java
@@ -25,6 +25,7 @@
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
+import org.primesoft.mcpainter.BlocksHubIntegration;
/**
*
@@ -32,9 +33,12 @@
*/
public class WorldEditLocalSession implements ILocalSession {
private final LocalSession m_localSession;
+
+ private final BlocksHubIntegration m_bh;
- public WorldEditLocalSession(LocalSession localSession) {
+ public WorldEditLocalSession(LocalSession localSession, BlocksHubIntegration bh) {
m_localSession = localSession;
+ m_bh = bh;
}
public LocalSession getLocalSession() {
@@ -57,6 +61,6 @@ public IEditSession createEditSession(ILocalPlayer localPlayer) {
}
EditSession session = m_localSession.createEditSession(((WorldEditLocalPlayer)localPlayer).getLocalPlayer());
- return new WorldEditEditSession(session);
+ return new WorldEditEditSession(localPlayer, session, m_bh);
}
}
diff --git a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/WorldEditWrapper.java b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/WorldEditWrapper.java
index e8a6507..3a50080 100644
--- a/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/WorldEditWrapper.java
+++ b/MCPainter/src/main/java/org/primesoft/mcpainter/worldEdit/WorldEditWrapper.java
@@ -21,32 +21,37 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-
package org.primesoft.mcpainter.worldEdit;
-import com.sk89q.worldedit.LocalPlayer;
+import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalSession;
+import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
-import com.sk89q.worldedit.bukkit.selections.CuboidSelection;
-import com.sk89q.worldedit.bukkit.selections.Selection;
+import com.sk89q.worldedit.regions.Region;
+import com.sk89q.worldedit.world.block.BlockState;
+import org.bukkit.Bukkit;
+import org.bukkit.Server;
+import org.bukkit.World;
import org.primesoft.mcpainter.utils.BaseBlock;
import org.primesoft.mcpainter.utils.Vector;
-import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
+import org.primesoft.mcpainter.BlocksHubIntegration;
/**
*
* @author SBPrime
*/
-public class WorldEditWrapper implements IWorldEdit {
+class WorldEditWrapper implements IWorldEdit {
+
private final WorldEditPlugin m_worldEdit;
-
- public WorldEditWrapper(Plugin wePlugin) {
- m_worldEdit = (WorldEditPlugin)wePlugin;
+ private final BlocksHubIntegration m_bh;
+
+ WorldEditWrapper(Plugin wePlugin, BlocksHubIntegration bh) {
+ m_bh = bh;
+ m_worldEdit = (WorldEditPlugin) wePlugin;
}
-
-
+
@Override
public boolean isRealWorldEdit() {
return true;
@@ -55,39 +60,66 @@ public boolean isRealWorldEdit() {
@Override
public ILocalSession getSession(Player player) {
LocalSession lSession = m_worldEdit.getSession(player);
- return new WorldEditLocalSession(lSession);
+ return new WorldEditLocalSession(lSession, m_bh);
}
@Override
public ILocalPlayer wrapPlayer(Player player) {
- LocalPlayer lPlayer = m_worldEdit.wrapPlayer(player);
- return new WorldEditLocalPlayer(lPlayer);
+ com.sk89q.worldedit.entity.Player lPlayer = m_worldEdit.wrapPlayer(player);
+ return new WorldEditLocalPlayer(lPlayer, player);
}
@Override
- public ICuboidSelection getSelection(Player player) {
- Selection selection = m_worldEdit.getSelection(player);
- if (!(selection instanceof CuboidSelection)) {
+ public CuboidSelection getSelection(Player player) {
+ LocalSession session = m_worldEdit.getSession(player);
+ final com.sk89q.worldedit.world.World sWorld = session.getSelectionWorld();
+ if (sWorld == null) {
+ return null;
+ }
+
+ Region selection = null;
+ try {
+ selection = session.getSelection(sWorld);
+ } catch (IncompleteRegionException ex) {
+ //Simply ignore me
+ }
+
+ if (selection == null) {
return null;
}
-
- return new WorldEditCuboidSelection((CuboidSelection)selection);
+
+ com.sk89q.worldedit.Vector pMin = selection.getMinimumPoint();
+ com.sk89q.worldedit.Vector pMax = selection.getMaximumPoint();
+
+ Server s = Bukkit.getServer();
+ World w = s.getWorld(sWorld.getName());
+
+ return new CuboidSelection(w,
+ new Vector(pMin.getX(), pMin.getY(), pMin.getZ()),
+ new Vector(pMax.getX(), pMax.getY(), pMax.getZ())
+ );
}
-
-
- public static com.sk89q.worldedit.Vector convert(Vector v) {
+
+ static com.sk89q.worldedit.Vector convert(Vector v) {
return new com.sk89q.worldedit.Vector(v.getX(), v.getY(), v.getZ());
}
- public static Vector convert(com.sk89q.worldedit.Vector v) {
+ static Vector convert(com.sk89q.worldedit.Vector v) {
return new Vector(v.getX(), v.getY(), v.getZ());
}
-
- public static com.sk89q.worldedit.blocks.BaseBlock convert(BaseBlock v) {
- return new com.sk89q.worldedit.blocks.BaseBlock(v.getType(), v.getData());
+
+ static com.sk89q.worldedit.world.block.BlockState convert(BaseBlock v) {
+ return BukkitAdapter.adapt(v.Data);
}
-
- public static BaseBlock convert(com.sk89q.worldedit.blocks.BaseBlock v) {
- return new BaseBlock(Material.getMaterial(v.getType()), v.getData());
+
+ static BaseBlock convert(com.sk89q.worldedit.world.block.BlockState v) {
+ return new BaseBlock(BukkitAdapter.adapt(v));
+ }
+
+ @Override
+ public void undo(Player player) {
+ com.sk89q.worldedit.entity.Player lPlayer = m_worldEdit.wrapPlayer(player);
+ m_worldEdit.getSession(player).undo(null, lPlayer);
+
}
}
diff --git a/MCPainter/src/main/resources/plugin.yml b/MCPainter/src/main/resources/plugin.yml
index ca3e341..c24819a 100644
--- a/MCPainter/src/main/resources/plugin.yml
+++ b/MCPainter/src/main/resources/plugin.yml
@@ -1,6 +1,7 @@
name: MCPainter
main: org.primesoft.mcpainter.MCPainterMain
version: 1.0.1
+api-version: 1.13
website: https://github.com/SBPrime/MCPainter/wiki
dev-url: https://github.com/SBPrime/MCPainter/wiki
description: Provides some basic features to draw using blocks.