diff --git a/.gitignore b/.gitignore index 32c274ae..b496ca8c 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ *.classpath /target/ /.gradle -/.idea \ No newline at end of file +/.idea +/forge/build \ No newline at end of file diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/BukkitPlayer.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/BukkitPlayer.java index 55296e6e..000d6782 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/BukkitPlayer.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/BukkitPlayer.java @@ -1,15 +1,13 @@ package com.boydti.fawe.bukkit; -import java.util.UUID; - -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Location; -import org.bukkit.entity.Player; - import com.boydti.fawe.Fawe; import com.boydti.fawe.object.FaweLocation; import com.boydti.fawe.object.FawePlayer; +import java.util.UUID; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.entity.Player; public class BukkitPlayer extends FawePlayer { diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java index 8afdacad..dd401a27 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java @@ -1,16 +1,5 @@ package com.boydti.fawe.bukkit; -import java.io.File; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Collection; - -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.java.JavaPlugin; - import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweAPI; import com.boydti.fawe.IFawe; @@ -35,6 +24,15 @@ import com.boydti.fawe.util.StringMan; import com.boydti.fawe.util.TaskManager; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import java.io.File; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collection; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.java.JavaPlugin; public class FaweBukkit extends JavaPlugin implements IFawe { @@ -63,7 +61,7 @@ public class FaweBukkit extends JavaPlugin implements IFawe { } catch (final Throwable e) { e.printStackTrace(); } - } catch (final Exception e) { + } catch (final Throwable e) { e.printStackTrace(); this.getServer().shutdown(); } @@ -95,6 +93,13 @@ public class FaweBukkit extends JavaPlugin implements IFawe { } } + @Override + public void startMetrics() { + Metrics metrics = new Metrics(this); + metrics.start(); + debug("&6Metrics enabled."); + } + /** * Kinda a really messy class I just copied over from an old project
* - Still works, so cbf cleaning it up
diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/Metrics.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/Metrics.java new file mode 100644 index 00000000..16d97623 --- /dev/null +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/Metrics.java @@ -0,0 +1,593 @@ +package com.boydti.fawe.bukkit; + +import com.boydti.fawe.Fawe; +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.InvocationTargetException; +import java.net.Proxy; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLEncoder; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.UUID; +import java.util.logging.Level; +import java.util.zip.GZIPOutputStream; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginDescriptionFile; +import org.bukkit.scheduler.BukkitTask; + +public class Metrics { + + /** + * The current revision number. + */ + private static final int REVISION = 7; + /** + * The base url of the metrics domain. + */ + 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 = "/plugin/%s"; + /** + * Interval of time to ping (in minutes). + */ + private static final int PING_INTERVAL = 15; + /** + * 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()); + /** + * Unique server id. + */ + private final String guid; + /** + * Debug mode. + */ + private final boolean debug; + /** + * The scheduled task. + */ + private volatile BukkitTask task = null; + + public Metrics(Plugin plugin) { + if (plugin == null) { + throw new IllegalArgumentException("Plugin cannot be null"); + } + this.plugin = plugin; + this.guid = UUID.randomUUID().toString(); + this.debug = false; + } + + /** + * GZip compress a string of bytes. + * + * @param input + * + * @return byte[] the file as a byte array + */ + 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(); + } + + /** + * Appends a json encoded key/value pair to the given string builder. + * + * @param json + * @param key + * @param value + * + */ + private static void appendJSONPair(StringBuilder json, String key, String value) { + 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 String + */ + 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 urlEncode(String text) throws UnsupportedEncodingException { + return URLEncoder.encode(text, "UTF-8"); + } + + /** + * 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(String name) { + if (name == null) { + throw new IllegalArgumentException("Graph name cannot be null"); + } + // Construct the graph object + Graph graph = new Graph(name); + // Now we can add our graph + this.graphs.add(graph); + // and return back + return graph; + } + + /** + * Add a Graph object to BukkitMetrics that represents data for the plugin that should be sent to the backend + * + * @param graph The name of the graph + */ + public void addGraph(Graph graph) { + if (graph == null) { + throw new IllegalArgumentException("Graph cannot be null"); + } + this.graphs.add(graph); + } + + /** + * 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() { + // Is metrics already running? + if (this.task != null) { + return true; + } + // Begin hitting the server with glorious data + this.task = this.plugin.getServer().getScheduler().runTaskTimerAsynchronously(this.plugin, new Runnable() { + private boolean firstPost = true; + + @Override + public void run() { + try { + postPlugin(!this.firstPost); + // After the first post we set firstPost to + // false + // Each post thereafter will be a ping + this.firstPost = false; + } catch (IOException e) { + e.printStackTrace(); + if (Metrics.this.debug) { + Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage()); + } + } + } + }, 0, PING_INTERVAL * 1200); + return true; + } + + /** + * Enables metrics for the server by setting "opt-out" to false in the config file and starting the metrics task. + * + * @throws java.io.IOException + */ + public void enable() { + // Enable Task, if it is not running + if (this.task == null) { + start(); + } + } + + /** + * Disables metrics for the server by setting "opt-out" to true in the config file and canceling the metrics task. + * + */ + public void disable() { + // Disable Task, if it is running + if (this.task != null) { + this.task.cancel(); + this.task = null; + } + } + + /** + * 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 = this.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(boolean isPing) throws IOException { + // Server software specific section + PluginDescriptionFile description = this.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 = 0; + try { + if (Bukkit.class.getMethod("getOnlinePlayers", new Class[0]).getReturnType() == Collection.class) { + playersOnline = ((Collection) Bukkit.class.getMethod("getOnlinePlayers", new Class[0]).invoke(null)).size(); + } else { + playersOnline = ((Player[]) Bukkit.class.getMethod("getOnlinePlayers", new Class[0]).invoke(null)).length; + } + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ex) { + ex.printStackTrace(); + } + // 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 containing all of the plugin data such as name, version, author, etc + appendJSONPair(json, "guid", this.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"; + } + 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) { + appendJSONPair(json, "ping", "1"); + } + if (!this.graphs.isEmpty()) { + synchronized (this.graphs) { + json.append(','); + json.append('"'); + json.append("graphs"); + json.append('"'); + json.append(':'); + json.append('{'); + boolean firstGraph = true; + for (Graph graph : this.graphs) { + StringBuilder graphJson = new StringBuilder(); + graphJson.append('{'); + for (Plotter plotter : graph.getPlotters()) { + appendJSONPair(graphJson, plotter.getColumnName(), Integer.toString(plotter.getValue())); + } + graphJson.append('}'); + if (!firstGraph) { + json.append(','); + } + json.append(escapeJSON(graph.getName())); + json.append(':'); + json.append(graphJson); + firstGraph = false; + } + json.append('}'); + } + } + // close json + json.append('}'); + // Create the url + URL url = new URL(BASE_URL + String.format(REPORT_URL, urlEncode(pluginName))); + // 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(); + } + 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 (this.debug) { + Fawe.debug("[Metrics] Prepared request for " + pluginName + " uncompressed=" + uncompressed.length + " compressed=" + compressed.length); + } + try { + try (OutputStream os = connection.getOutputStream()) { + os.write(compressed); + os.flush(); + } + String response; + try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) { + response = reader.readLine(); + if (this.debug) { + Fawe.debug("[Metrics] Response for " + pluginName + ": " + response); + } + } + 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); + } else { + // Is this the first update this hour? + if ("1".equals(response) || response.contains("This is your first update this hour")) { + synchronized (this.graphs) { + for (Graph graph : this.graphs) { + for (Plotter plotter : graph.getPlotters()) { + plotter.reset(); + } + } + } + } + } + } catch (Exception e) { + if (this.debug) { + e.printStackTrace(); + } + } + } + + /** + * 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 (ClassNotFoundException e) { + return false; + } + } + + /** + * 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(String name) { + this.name = name; + } + + /** + * Gets the graph's name + * + * @return the Graph's name + */ + public String getName() { + return this.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(Plotter plotter) { + this.plotters.add(plotter); + } + + /** + * Remove a plotter from the graph + * + * @param plotter the plotter to remove from the graph + */ + public void removePlotter(Plotter plotter) { + this.plotters.remove(plotter); + } + + /** + * Gets an unmodifiable set of the plotter objects in the graph + * + * @return an unmodifiable {@link java.util.Set} of the plotter objects + */ + public Set getPlotters() { + return Collections.unmodifiableSet(this.plotters); + } + + @Override + public int hashCode() { + return this.name.hashCode(); + } + + @Override + public boolean equals(Object object) { + if (!(object instanceof Graph)) { + return false; + } + Graph graph = (Graph) object; + return graph.name.equals(this.name); + } + + /** + * Called when the server owner decides to opt-out of BukkitMetrics while the server is running. + */ + protected void onOptOut() { + } + } + + /** + * Interface used to collect custom data for a plugin + */ + public abstract static 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(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 this.name; + } + + /** + * Called after the website graphs have been updated + */ + public void reset() { + } + + @Override + public int hashCode() { + return getColumnName().hashCode(); + } + + @Override + public boolean equals(Object object) { + if (!(object instanceof Plotter)) { + return false; + } + Plotter plotter = (Plotter) object; + return plotter.name.equals(this.name) && plotter.getValue() == getValue(); + } + } +} \ No newline at end of file diff --git a/core/src/main/java/com/boydti/fawe/IFawe.java b/core/src/main/java/com/boydti/fawe/IFawe.java index aecf07cb..c8573357 100644 --- a/core/src/main/java/com/boydti/fawe/IFawe.java +++ b/core/src/main/java/com/boydti/fawe/IFawe.java @@ -33,4 +33,6 @@ public interface IFawe { public EditSessionWrapper getEditSessionWrapper(final EditSession session); public Collection getMaskManagers(); + + public void startMetrics(); } diff --git a/core/src/main/java/com/boydti/fawe/config/BBC.java b/core/src/main/java/com/boydti/fawe/config/BBC.java index cf2bcb3c..d69e92e4 100644 --- a/core/src/main/java/com/boydti/fawe/config/BBC.java +++ b/core/src/main/java/com/boydti/fawe/config/BBC.java @@ -179,6 +179,10 @@ public enum BBC { } } + public static String color(String string) { + return StringMan.replaceFromMap(string, replacements); + } + public String s() { return this.s; } diff --git a/core/src/main/java/com/boydti/fawe/regions/general/PlotSquaredFeature.java b/core/src/main/java/com/boydti/fawe/regions/general/PlotSquaredFeature.java new file mode 100644 index 00000000..c348abaa --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/regions/general/PlotSquaredFeature.java @@ -0,0 +1,74 @@ +package com.boydti.fawe.regions.general; + +import com.boydti.fawe.object.FawePlayer; +import com.boydti.fawe.regions.FaweMask; +import com.boydti.fawe.regions.FaweMaskManager; +import com.intellectualcrafters.plot.PS; +import com.intellectualcrafters.plot.object.Location; +import com.intellectualcrafters.plot.object.Plot; +import com.intellectualcrafters.plot.object.PlotId; +import com.intellectualcrafters.plot.object.PlotPlayer; +import com.intellectualcrafters.plot.object.RegionWrapper; +import java.util.HashSet; + +public class PlotSquaredFeature extends FaweMaskManager { + public PlotSquaredFeature() { + super("PlotSquared"); + PS.get().worldedit = null; + } + + @Override + public FaweMask getMask(FawePlayer fp) { + final PlotPlayer pp = PlotPlayer.wrap(fp.parent); + Plot plot = pp.getCurrentPlot(); + Location loc = pp.getLocation(); + final String world = loc.getWorld(); + if (plot == null) { + int min = Integer.MAX_VALUE; + for (final Plot p : pp.getPlots()) { + if (p.getArea().worldname.equals(world)) { + final double d = p.getHome().getEuclideanDistanceSquared(loc); + if (d < min) { + min = (int) d; + plot = p; + } + } + } + } + if (plot != null) { + final PlotId id = plot.getId(); + boolean hasPerm = false; + if (plot.owner != null) { + if (plot.owner.equals(pp.getUUID())) { + hasPerm = true; + } else if (plot.isAdded(pp.getUUID()) && pp.hasPermission("fawe.plotsquared.member")) { + hasPerm = true; + } + if (hasPerm) { + RegionWrapper region = plot.getLargestRegion(); + HashSet regions = plot.getRegions(); + + final Location pos1 = new Location(world, region.minX, 0, region.minZ); + final Location pos2 = new Location(world, region.maxX, 256, region.maxZ); + + final HashSet faweRegions = new HashSet(); + for (final com.intellectualcrafters.plot.object.RegionWrapper current : regions) { + faweRegions.add(new com.boydti.fawe.object.RegionWrapper(current.minX, current.maxX, current.minZ, current.maxZ)); + } + return new BukkitMask(pos1, pos2) { + @Override + public String getName() { + return "PLOT^2:" + id; + } + + @Override + public HashSet getRegions() { + return faweRegions; + } + }; + } + } + } + return null; + } +} diff --git a/forge/build.gradle b/forge/build.gradle index ec7e5d8f..f670fa4a 100644 --- a/forge/build.gradle +++ b/forge/build.gradle @@ -20,6 +20,7 @@ dependencies { compile project(':core') compile 'org.spongepowered:spongeapi:4.+' compile 'org.mcstats.sponge:metrics:R8-SNAPSHOT' + compile 'com.sk89q.worldedit:worldedit-forge-mc1.8.9:6.1.1' } sourceCompatibility = 1.8 diff --git a/forge/src/main/java/com/boydti/fawe/forge/FaweSponge.java b/forge/src/main/java/com/boydti/fawe/forge/FaweSponge.java new file mode 100644 index 00000000..33354baa --- /dev/null +++ b/forge/src/main/java/com/boydti/fawe/forge/FaweSponge.java @@ -0,0 +1,155 @@ +package com.boydti.fawe.forge; + +import com.boydti.fawe.Fawe; +import com.boydti.fawe.IFawe; +import com.boydti.fawe.config.BBC; +import com.boydti.fawe.object.EditSessionWrapper; +import com.boydti.fawe.object.FaweCommand; +import com.boydti.fawe.object.FawePlayer; +import com.boydti.fawe.regions.FaweMaskManager; +import com.boydti.fawe.util.FaweQueue; +import com.boydti.fawe.util.TaskManager; +import com.google.inject.Inject; +import com.intellectualcrafters.plot.config.C; +import com.intellectualcrafters.plot.config.Settings; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.forge.ForgeWorldEdit; +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import org.mcstats.Metrics; +import org.slf4j.Logger; +import org.spongepowered.api.Game; +import org.spongepowered.api.Server; +import org.spongepowered.api.event.Listener; +import org.spongepowered.api.event.game.state.GameAboutToStartServerEvent; +import org.spongepowered.api.plugin.Plugin; +import org.spongepowered.api.plugin.PluginContainer; +import org.spongepowered.api.profile.GameProfileManager; +import org.spongepowered.api.text.serializer.TextSerializers; + +@Plugin(id = "com.boydti.fawe", name = "FastAsyncWorldEdit", description = "Lagless WorldEdit, Area restrictions, Memory mangement, Block logging", url = "https://github.com/boy0001/FastAsyncWorldedit", version = "3.3.4") +public class FaweSponge implements IFawe { + public PluginContainer plugin; + public FaweSponge instance; + + @Inject + private Logger logger; + @Inject + private Game game; + private Server server; + + private GameProfileManager resolver; + + private ForgeWorldEdit worldedit; + + public ForgeWorldEdit getWorldEditPlugin() { + if (this.worldedit == null) { + this.worldedit = ForgeWorldEdit.inst; + } + return this.worldedit; + } + + public Game getGame() { + return this.game; + } + + public Server getServer() { + return this.server; + } + + public GameProfileManager getResolver() { + if (this.resolver == null) { + this.resolver = this.game.getServer().getGameProfileManager(); + } + return this.resolver; + } + + @Listener + public void onServerAboutToStart(GameAboutToStartServerEvent event) { + debug("FAWE: Server init"); + instance = this; + plugin = this.game.getPluginManager().fromInstance(this).get(); + this.server = this.game.getServer(); + try { + Fawe.set(this); + } catch (final Throwable e) { + e.printStackTrace(); + this.getServer().shutdown(); + } + } + + @Override + public void debug(String message) { + message = C.format(message, C.replacements); + if (!Settings.CONSOLE_COLOR) { + message = message.replaceAll('\u00a7' + "[a-z|0-9]", ""); + } + if (this.server == null) { + this.logger.info(message); + return; + } + this.server.getConsole().sendMessage(TextSerializers.LEGACY_FORMATTING_CODE.deserialize(BBC.color(message))); + } + + @Override + public File getDirectory() { + return new File("mods/FastAsyncWorldEdit"); + } + + @Override + public void setupCommand(String label, FaweCommand cmd) { + + } + + @Override + public FawePlayer wrap(Object obj) { + return null; + } + + @Override + public void setupWEListener() { + + } + + @Override + public void setupVault() { + + } + + @Override + public TaskManager getTaskManager() { + return null; + } + + @Override + public int[] getVersion() { + return new int[0]; + } + + @Override + public FaweQueue getQueue() { + return null; + } + + @Override + public EditSessionWrapper getEditSessionWrapper(EditSession session) { + return null; + } + + @Override + public Collection getMaskManagers() { + return null; + } + + @Override + public void startMetrics() { + try { + Metrics metrics = new Metrics(this.game, this.plugin); + metrics.start(); + debug(C.PREFIX.s() + "&6Metrics enabled."); + } catch (IOException e) { + debug(C.PREFIX.s() + "&cFailed to load up metrics."); + } + } +} diff --git a/forge/src/main/java/com/boydti/fawe/forge/SpongeCommand.java b/forge/src/main/java/com/boydti/fawe/forge/SpongeCommand.java new file mode 100644 index 00000000..7c8cd99d --- /dev/null +++ b/forge/src/main/java/com/boydti/fawe/forge/SpongeCommand.java @@ -0,0 +1,57 @@ +package com.boydti.fawe.forge; + +import com.boydti.fawe.Fawe; +import com.boydti.fawe.config.BBC; +import com.boydti.fawe.object.FaweCommand; +import com.boydti.fawe.object.FawePlayer; +import java.util.List; +import java.util.Optional; +import org.spongepowered.api.command.CommandCallable; +import org.spongepowered.api.command.CommandException; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.text.Text; + +/** + * Created by Jesse on 4/2/2016. + */ +public class SpongeCommand implements CommandCallable { + + private final FaweCommand cmd; + + public SpongeCommand(final FaweCommand cmd) { + this.cmd = cmd; + } + + @Override + public CommandResult process(CommandSource source, String args) throws CommandException { + final FawePlayer plr = Fawe.imp().wrap(source); + if (!source.hasPermission(this.cmd.getPerm())) { + BBC.NO_PERM.send(plr, this.cmd.getPerm()); + return CommandResult.success(); + } + this.cmd.execute(plr, args.split(" ")); + return CommandResult.success(); + } + + @Override + public List getSuggestions(CommandSource source, String arguments) throws CommandException {return null;} + + @Override + public boolean testPermission(CommandSource source) {return true;} + + @Override + public Optional getShortDescription(final CommandSource cmd) { + return Optional.of(Text.of("Various")); + } + + @Override + public Optional getHelp(final CommandSource cmd) { + return Optional.of(Text.of("/")); + } + + @Override + public Text getUsage(final CommandSource cmd) { + return Text.of("/"); + } +} diff --git a/forge/src/main/java/com/boydti/fawe/forge/SpongePlayer.java b/forge/src/main/java/com/boydti/fawe/forge/SpongePlayer.java new file mode 100644 index 00000000..9dfc85a3 --- /dev/null +++ b/forge/src/main/java/com/boydti/fawe/forge/SpongePlayer.java @@ -0,0 +1,61 @@ +package com.boydti.fawe.forge; + +import com.boydti.fawe.Fawe; +import com.boydti.fawe.config.BBC; +import com.boydti.fawe.object.FaweLocation; +import com.boydti.fawe.object.FawePlayer; +import java.util.UUID; +import net.minecraft.entity.player.EntityPlayerMP; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.text.serializer.TextSerializers; +import org.spongepowered.api.world.Location; +import org.spongepowered.api.world.World; + +public class SpongePlayer extends FawePlayer { + public SpongePlayer(final Player parent) { + super(parent); + } + + @Override + public String getName() { + return this.parent.getName(); + } + + @Override + public UUID getUUID() { + return this.parent.getUniqueId(); + } + + @Override + public boolean hasPermission(final String perm) { + return this.parent.hasPermission(perm); + } + + @Override + public void setPermission(final String perm, final boolean flag) { + throw new UnsupportedOperationException("WIP NOT IMPLEMENTED YET TODO"); // TODO FIXME + } + + @Override + public void sendMessage(final String message) { + this.parent.sendMessage(TextSerializers.LEGACY_FORMATTING_CODE.deserialize(BBC.color(message))); + } + + @Override + public void executeCommand(final String cmd) { + Sponge.getGame().getCommandManager().process(this.parent, cmd); + } + + @Override + public FaweLocation getLocation() { + Location loc = this.parent.getLocation(); + return new FaweLocation(loc.getExtent().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); + } + + @Override + public com.sk89q.worldedit.entity.Player getPlayer() { + return (com.sk89q.worldedit.entity.Player) Fawe. imp().getWorldEditPlugin().wrap((EntityPlayerMP) this.parent); + } + +}