Mainly formatting and some work on schematic commands

This commit is contained in:
MattBDev 2019-07-22 22:22:32 -04:00
parent 46f5b12b36
commit b230999ca0
28 changed files with 796 additions and 656 deletions

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC <!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN" "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd"> "https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker"> <module name="Checker">
<!-- Tabs are strictly banned --> <!-- Tabs are strictly banned -->
<module name="FileTabCharacter"/> <module name="FileTabCharacter"/>
@ -16,9 +16,11 @@
Control package usage, so people don't insert Bukkit into WE where it shouldn't belong, etc. Control package usage, so people don't insert Bukkit into WE where it shouldn't belong, etc.
It is a bit draconian, so update as necessary! It is a bit draconian, so update as necessary!
--> -->
<!--
<module name="ImportControl"> <module name="ImportControl">
<property name="file" value="${basedir}/config/checkstyle/import-control.xml"/> <property name="file" value="import-control.xml"/>
</module> </module>
-->
<!-- Code --> <!-- Code -->
<module name="HideUtilityClassConstructor"/> <!-- Utility classes should not have a constructor --> <module name="HideUtilityClassConstructor"/> <!-- Utility classes should not have a constructor -->
@ -63,6 +65,10 @@
<property name="format" value="(?!Character)\.to(Lower|Upper)Case\(\)"/> <property name="format" value="(?!Character)\.to(Lower|Upper)Case\(\)"/>
<property name="illegalPattern" value="true"/> <property name="illegalPattern" value="true"/>
</module> </module>
<module name="EmptyCatchBlock">
<property name="exceptionVariableName" value="ignored|ignore"/>
</module>
</module> </module>
<!-- Validate that command annotations are formatted correctly --> <!-- Validate that command annotations are formatted correctly -->
<module name="RegexpMultiline"> <module name="RegexpMultiline">

View File

@ -30,7 +30,7 @@ public class HelpJSAP extends JSAP {
* @param explanation * @param explanation
* @param screenWidth * @param screenWidth
*/ */
public HelpJSAP(final String name, final String explanation, final int screenWidth) { public HelpJSAP(String name, String explanation, int screenWidth) {
super(); super();
this.name = name; this.name = name;
@ -39,7 +39,7 @@ public class HelpJSAP extends JSAP {
try { try {
this.registerParameter(new Switch("help", JSAP.NO_SHORTFLAG, "help", "Displays this help page.")); this.registerParameter(new Switch("help", JSAP.NO_SHORTFLAG, "help", "Displays this help page."));
} catch (final JSAPException e) { } catch (JSAPException ignored) {
} }
} }
@ -48,10 +48,10 @@ public class HelpJSAP extends JSAP {
* @param explanation * @param explanation
* @param screenWidth * @param screenWidth
* @param resourceName * @param resourceName
* @throws java.io.IOException if an I/O error occurs * @throws IOException if an I/O error occurs
* @throws com.martiansoftware.jsap.JSAPException if the configuration is not valid * @throws JSAPException if the configuration is not valid
*/ */
public HelpJSAP(final String name, final String explanation, final int screenWidth, final String resourceName) throws IOException, JSAPException { public HelpJSAP(String name, String explanation, int screenWidth, String resourceName) throws IOException, JSAPException {
super(resourceName); super(resourceName);
this.name = name; this.name = name;
@ -60,7 +60,7 @@ public class HelpJSAP extends JSAP {
try { try {
this.registerParameter(new Switch("help", JSAP.NO_SHORTFLAG, "help", "Displays this help page.")); this.registerParameter(new Switch("help", JSAP.NO_SHORTFLAG, "help", "Displays this help page."));
} catch (final JSAPException e) { } catch (JSAPException ignored) {
} }
} }
@ -69,10 +69,10 @@ public class HelpJSAP extends JSAP {
* @param explanation * @param explanation
* @param screenWidth * @param screenWidth
* @param jsapXML * @param jsapXML
* @throws java.io.IOException if an I/O error occurs * @throws IOException if an I/O error occurs
* @throws com.martiansoftware.jsap.JSAPException if the configuration is not valid * @throws JSAPException if the configuration is not valid
*/ */
public HelpJSAP(final String name, final String explanation, final int screenWidth, final URL jsapXML) throws IOException, JSAPException { public HelpJSAP(String name, String explanation, int screenWidth, URL jsapXML) throws IOException, JSAPException {
super(jsapXML); super(jsapXML);
this.name = name; this.name = name;
@ -81,7 +81,7 @@ public class HelpJSAP extends JSAP {
try { try {
this.registerParameter(new Switch("help", JSAP.NO_SHORTFLAG, "help", "Displays this help page.")); this.registerParameter(new Switch("help", JSAP.NO_SHORTFLAG, "help", "Displays this help page."));
} catch (final JSAPException e) { } catch (JSAPException ignored) {
} }
} }
@ -95,7 +95,7 @@ public class HelpJSAP extends JSAP {
/** /**
* @param explanation the explanation to set * @param explanation the explanation to set
*/ */
public final void setExplanation(final String explanation) { public final void setExplanation(String explanation) {
this.explanation = explanation; this.explanation = explanation;
} }
@ -109,7 +109,7 @@ public class HelpJSAP extends JSAP {
/** /**
* @param name the name to set * @param name the name to set
*/ */
public final void setName(final String name) { public final void setName(String name) {
this.name = name; this.name = name;
} }
@ -123,7 +123,7 @@ public class HelpJSAP extends JSAP {
/** /**
* @param screenWidth the screenWidth to set * @param screenWidth the screenWidth to set
*/ */
public final void setScreenWidth(final int screenWidth) { public final void setScreenWidth(int screenWidth) {
this.screenWidth = screenWidth; this.screenWidth = screenWidth;
} }
@ -131,8 +131,8 @@ public class HelpJSAP extends JSAP {
* @param jsapResult * @param jsapResult
* @return if something has been written on writer. * @return if something has been written on writer.
*/ */
public final List<String> writeHelpOrErrorMessageIfRequired(final JSAPResult jsapResult) { public final List<String> writeHelpOrErrorMessageIfRequired(JSAPResult jsapResult) {
if (!(jsapResult.success()) || jsapResult.getBoolean("help")) { if (!jsapResult.success() || jsapResult.getBoolean("help")) {
List<String> returnValue = new LinkedList<>(); List<String> returnValue = new LinkedList<>();
// To avoid spurious missing argument errors we never print errors if help is required. // To avoid spurious missing argument errors we never print errors if help is required.
if (!jsapResult.getBoolean("help")) { if (!jsapResult.getBoolean("help")) {
@ -145,14 +145,14 @@ public class HelpJSAP extends JSAP {
returnValue.add(ChatColor.GOLD + "Usage:"); returnValue.add(ChatColor.GOLD + "Usage:");
List<?> l = StringUtils.wrapToList(this.name + " " + this.getUsage(), this.screenWidth); List<?> l = StringUtils.wrapToList(this.name + " " + this.getUsage(), this.screenWidth);
for (final Object aL : l) { for (Object aL : l) {
returnValue.add(" " + aL.toString()); returnValue.add(" " + aL.toString());
} }
if (this.explanation != null) { if (this.explanation != null) {
returnValue.add(""); returnValue.add("");
l = StringUtils.wrapToList(this.explanation, this.screenWidth); l = StringUtils.wrapToList(this.explanation, this.screenWidth);
for (final Object aL : l) { for (Object aL : l) {
final String next = (String) aL; final String next = (String) aL;
returnValue.add(ChatColor.AQUA + next); returnValue.add(ChatColor.AQUA + next);
} }

View File

@ -45,15 +45,15 @@ public class BukkitPlayer extends FawePlayer<Player> {
* Permissions are used to managing WorldEdit region restrictions * Permissions are used to managing WorldEdit region restrictions
* - The `/wea` command will give/remove the required bypass permission * - The `/wea` command will give/remove the required bypass permission
*/ */
if (Fawe.<FaweBukkit>imp().getVault() == null || Fawe.<FaweBukkit> imp().getVault().permission == null) { if (Fawe.<FaweBukkit>imp().getVault() == null || Fawe.<FaweBukkit>imp().getVault().permission == null) {
this.parent.addAttachment(Fawe.<FaweBukkit> imp().getPlugin()).setPermission(perm, flag); this.parent.addAttachment(Fawe.<FaweBukkit>imp().getPlugin()).setPermission(perm, flag);
} else if (flag) { } else if (flag) {
if (!Fawe.<FaweBukkit> imp().getVault().permission.playerAdd(this.parent, perm)) { if (!Fawe.<FaweBukkit>imp().getVault().permission.playerAdd(this.parent, perm)) {
this.parent.addAttachment(Fawe.<FaweBukkit> imp().getPlugin()).setPermission(perm, flag); this.parent.addAttachment(Fawe.<FaweBukkit>imp().getPlugin()).setPermission(perm, flag);
} }
} else { } else {
if (!Fawe.<FaweBukkit> imp().getVault().permission.playerRemove(this.parent, perm)) { if (!Fawe.<FaweBukkit>imp().getVault().permission.playerRemove(this.parent, perm)) {
this.parent.addAttachment(Fawe.<FaweBukkit> imp().getPlugin()).setPermission(perm, flag); this.parent.addAttachment(Fawe.<FaweBukkit>imp().getPlugin()).setPermission(perm, flag);
} }
} }
} }

View File

@ -1,5 +1,7 @@
package com.boydti.fawe.bukkit.chat; package com.boydti.fawe.bukkit.chat;
import static com.boydti.fawe.bukkit.chat.TextualComponent.rawText;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
@ -12,10 +14,16 @@ import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.*; import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.logging.Level; import java.util.logging.Level;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -24,20 +32,22 @@ import org.bukkit.configuration.serialization.ConfigurationSerialization;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import static com.boydti.fawe.bukkit.chat.TextualComponent.rawText;
/** /**
* Represents a formattable message. Such messages can use elements such as colors, formatting codes, hover and click data, and other features provided by the vanilla Minecraft <a href="http://minecraft.gamepedia.com/Tellraw#Raw_JSON_Text">JSON message formatter</a>. * Represents a formattable message. Such messages can use elements such as colors, formatting
* This class allows plugins to emulate the functionality of the vanilla Minecraft <a href="http://minecraft.gamepedia.com/Commands#tellraw">tellraw command</a>. * codes, hover and click data, and other features provided by the vanilla Minecraft <a
* href="http://minecraft.gamepedia.com/Tellraw#Raw_JSON_Text">JSON message formatter</a>. This
* class allows plugins to emulate the functionality of the vanilla Minecraft <a
* href="http://minecraft.gamepedia.com/Commands#tellraw">tellraw command</a>.
* <p> * <p>
* This class follows the builder pattern, allowing for method chaining. * This class follows the builder pattern, allowing for method chaining. It is set up such that
* It is set up such that invocations of property-setting methods will affect the current editing component, * invocations of property-setting methods will affect the current editing component, and a call to
* and a call to {@link #then()} or {@link #then(String)} will append a new editing component to the end of the message, * {@link #then()} or {@link #then(String)} will append a new editing component to the end of the
* optionally initializing it with text. Further property-setting method calls will affect that editing component. * message, optionally initializing it with text. Further property-setting method calls will affect
* that editing component.
* </p> * </p>
*/ */
public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<MessagePart>, ConfigurationSerializable { public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<MessagePart>,
ConfigurationSerializable {
static { static {
ConfigurationSerialization.registerClass(FancyMessage.class); ConfigurationSerialization.registerClass(FancyMessage.class);
@ -80,10 +90,12 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
dirty = false; dirty = false;
if (nmsPacketPlayOutChatConstructor == null) { if (nmsPacketPlayOutChatConstructor == null) {
try { try {
nmsPacketPlayOutChatConstructor = Reflection.getNMSClass("PacketPlayOutChat").getDeclaredConstructor(Reflection.getNMSClass("IChatBaseComponent")); nmsPacketPlayOutChatConstructor = Reflection.getNMSClass("PacketPlayOutChat")
.getDeclaredConstructor(Reflection.getNMSClass("IChatBaseComponent"));
nmsPacketPlayOutChatConstructor.setAccessible(true); nmsPacketPlayOutChatConstructor.setAccessible(true);
} catch (NoSuchMethodException e) { } catch (NoSuchMethodException e) {
Bukkit.getLogger().log(Level.SEVERE, "Could not find Minecraft method or constructor.", e); Bukkit.getLogger()
.log(Level.SEVERE, "Could not find Minecraft method or constructor.", e);
} catch (SecurityException e) { } catch (SecurityException e) {
Bukkit.getLogger().log(Level.WARNING, "Could not access constructor.", e); Bukkit.getLogger().log(Level.WARNING, "Could not access constructor.", e);
} }
@ -124,10 +136,10 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
/** /**
*
* @param text Text with coloring * @param text Text with coloring
* @return This builder instance. * @return This builder instance.
* @throws IllegalArgumentException If the specified {@code ChatColor} enumeration value is not a color (but a format value). * @throws IllegalArgumentException If the specified {@code ChatColor} enumeration value is not
* a color (but a format value).
*/ */
public FancyMessage color(String text) { public FancyMessage color(String text) {
index = messageParts.size(); index = messageParts.size();
@ -148,7 +160,7 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
last = i + 1; last = i + 1;
} }
} }
if (c == '\u00A7') { if (c == '\u00A7') {
color = true; color = true;
} }
} }
@ -161,12 +173,13 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
/** /**
* Sets the color of the current editing component to a value.<br /> * Sets the color of the current editing component to a value.<br /> Setting the color will
* Setting the color will clear current styles * clear current styles
* *
* @param color The new color of the current editing component. * @param color The new color of the current editing component.
* @return This builder instance. * @return This builder instance.
* @throws IllegalArgumentException If the specified {@code ChatColor} enumeration value is not a color (but a format value). * @throws IllegalArgumentException If the specified {@code ChatColor} enumeration value is not
* a color (but a format value).
*/ */
public FancyMessage color(ChatColor color) { public FancyMessage color(ChatColor color) {
if (!color.isColor()) { if (!color.isColor()) {
@ -189,7 +202,8 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
* *
* @param styles The array of styles to apply to the editing component. * @param styles The array of styles to apply to the editing component.
* @return This builder instance. * @return This builder instance.
* @throws IllegalArgumentException If any of the enumeration values in the array do not represent formatters. * @throws IllegalArgumentException If any of the enumeration values in the array do not
* represent formatters.
*/ */
public FancyMessage style(ChatColor... styles) { public FancyMessage style(ChatColor... styles) {
for (final ChatColor style : styles) { for (final ChatColor style : styles) {
@ -203,7 +217,9 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
/** /**
* Set the behavior of the current editing component to instruct the client to open a file on the client side filesystem when the currently edited part of the {@code FancyMessage} is clicked. * Set the behavior of the current editing component to instruct the client to open a file on
* the client side filesystem when the currently edited part of the {@code FancyMessage} is
* clicked.
* *
* @param path The path of the file on the client filesystem. * @param path The path of the file on the client filesystem.
* @return This builder instance. * @return This builder instance.
@ -214,7 +230,9 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
/** /**
* Set the behavior of the current editing component to instruct the client to open a webpage in the client's web browser when the currently edited part of the {@code FancyMessage} is clicked. * Set the behavior of the current editing component to instruct the client to open a webpage in
* the client's web browser when the currently edited part of the {@code FancyMessage} is
* clicked.
* *
* @param url The URL of the page to open when the link is clicked. * @param url The URL of the page to open when the link is clicked.
* @return This builder instance. * @return This builder instance.
@ -225,8 +243,11 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
/** /**
* Set the behavior of the current editing component to instruct the client to replace the chat input box content with the specified string when the currently edited part of the {@code FancyMessage} is clicked. * Set the behavior of the current editing component to instruct the client to replace the chat
* The client will not immediately send the command to the server to be executed unless the client player submits the command/chat message, usually with the enter key. * input box content with the specified string when the currently edited part of the {@code
* FancyMessage} is clicked. The client will not immediately send the command to the server to
* be executed unless the client player submits the command/chat message, usually with the enter
* key.
* *
* @param command The text to display in the chat bar of the client. * @param command The text to display in the chat bar of the client.
* @return This builder instance. * @return This builder instance.
@ -237,8 +258,11 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
/** /**
* Set the behavior of the current editing component to instruct the client to append the chat input box content with the specified string when the currently edited part of the {@code FancyMessage} is SHIFT-CLICKED. * Set the behavior of the current editing component to instruct the client to append the chat
* The client will not immediately send the command to the server to be executed unless the client player submits the command/chat message, usually with the enter key. * input box content with the specified string when the currently edited part of the {@code
* FancyMessage} is SHIFT-CLICKED. The client will not immediately send the command to the
* server to be executed unless the client player submits the command/chat message, usually with
* the enter key.
* *
* @param command The text to append to the chat bar of the client. * @param command The text to append to the chat bar of the client.
* @return This builder instance. * @return This builder instance.
@ -250,8 +274,10 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
/** /**
* Set the behavior of the current editing component to instruct the client to send the specified string to the server as a chat message when the currently edited part of the {@code FancyMessage} is clicked. * Set the behavior of the current editing component to instruct the client to send the
* The client <b>will</b> immediately send the command to the server to be executed when the editing component is clicked. * specified string to the server as a chat message when the currently edited part of the {@code
* FancyMessage} is clicked. The client <b>will</b> immediately send the command to the server
* to be executed when the editing component is clicked.
* *
* @param command The text to display in the chat bar of the client. * @param command The text to display in the chat bar of the client.
* @return This builder instance. * @return This builder instance.
@ -262,10 +288,13 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
/** /**
* Set the behavior of the current editing component to display raw text when the client hovers over the text. * Set the behavior of the current editing component to display raw text when the client hovers
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p> * over the text.
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the
* message component on which they are applied.</p>
* *
* @param text The text, which supports newlines, which will be displayed to the client upon hovering. * @param text The text, which supports newlines, which will be displayed to the client upon
* hovering.
* @return This builder instance. * @return This builder instance.
*/ */
public FancyMessage tooltip(final String text) { public FancyMessage tooltip(final String text) {
@ -274,10 +303,14 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
/** /**
* Set the behavior of the current editing component to display raw text when the client hovers over the text. * Set the behavior of the current editing component to display raw text when the client hovers
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p> * over the text.
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the
* message component on which they are applied.</p>
* *
* @param lines The lines of text which will be displayed to the client upon hovering. The iteration order of this object will be the order in which the lines of the tooltip are created. * @param lines The lines of text which will be displayed to the client upon hovering. The
* iteration order of this object will be the order in which the lines of the
* tooltip are created.
* @return This builder instance. * @return This builder instance.
*/ */
public FancyMessage tooltip(final Iterable<String> lines) { public FancyMessage tooltip(final Iterable<String> lines) {
@ -286,8 +319,10 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
/** /**
* Set the behavior of the current editing component to display raw text when the client hovers over the text. * Set the behavior of the current editing component to display raw text when the client hovers
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p> * over the text.
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the
* message component on which they are applied.</p>
* *
* @param lines The lines of text which will be displayed to the client upon hovering. * @param lines The lines of text which will be displayed to the client upon hovering.
* @return This builder instance. * @return This builder instance.
@ -305,8 +340,10 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
/** /**
* Set the behavior of the current editing component to display formatted text when the client hovers over the text. * Set the behavior of the current editing component to display formatted text when the client
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p> * hovers over the text.
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the
* message component on which they are applied.</p>
* *
* @param text The formatted text which will be displayed to the client upon hovering. * @param text The formatted text which will be displayed to the client upon hovering.
* @return This builder instance. * @return This builder instance.
@ -324,10 +361,13 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
/** /**
* Set the behavior of the current editing component to display the specified lines of formatted text when the client hovers over the text. * Set the behavior of the current editing component to display the specified lines of formatted
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p> * text when the client hovers over the text.
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the
* message component on which they are applied.</p>
* *
* @param lines The lines of formatted text which will be displayed to the client upon hovering. * @param lines The lines of formatted text which will be displayed to the client upon
* hovering.
* @return This builder instance. * @return This builder instance.
*/ */
public FancyMessage formattedTooltip(FancyMessage... lines) { public FancyMessage formattedTooltip(FancyMessage... lines) {
@ -337,15 +377,19 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
FancyMessage result = new FancyMessage(); FancyMessage result = new FancyMessage();
result.messageParts.clear(); // Remove the one existing text component that exists by default, which destabilizes the object result.messageParts
.clear(); // Remove the one existing text component that exists by default, which destabilizes the object
for (int i = 0; i < lines.length; i++) { for (int i = 0; i < lines.length; i++) {
try { try {
for (MessagePart component : lines[i]) { for (MessagePart component : lines[i]) {
if (component.clickActionData != null && component.clickActionName != null) { if (component.clickActionData != null && component.clickActionName != null) {
throw new IllegalArgumentException("The tooltip text cannot have click data."); throw new IllegalArgumentException(
} else if (component.hoverActionData != null && component.hoverActionName != null) { "The tooltip text cannot have click data.");
throw new IllegalArgumentException("The tooltip text cannot have a tooltip."); } else if (component.hoverActionData != null
&& component.hoverActionName != null) {
throw new IllegalArgumentException(
"The tooltip text cannot have a tooltip.");
} }
if (component.hasText()) { if (component.hasText()) {
result.messageParts.add(component.clone()); result.messageParts.add(component.clone());
@ -361,24 +405,32 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
return this; return this;
} }
} }
return formattedTooltip(result.messageParts.isEmpty() ? null : result); // Throws NPE if size is 0, intended return formattedTooltip(
result.messageParts.isEmpty() ? null : result); // Throws NPE if size is 0, intended
} }
/** /**
* Set the behavior of the current editing component to display the specified lines of formatted text when the client hovers over the text. * Set the behavior of the current editing component to display the specified lines of formatted
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p> * text when the client hovers over the text.
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the
* message component on which they are applied.</p>
* *
* @param lines The lines of text which will be displayed to the client upon hovering. The iteration order of this object will be the order in which the lines of the tooltip are created. * @param lines The lines of text which will be displayed to the client upon hovering. The
* iteration order of this object will be the order in which the lines of the
* tooltip are created.
* @return This builder instance. * @return This builder instance.
*/ */
public FancyMessage formattedTooltip(final Iterable<FancyMessage> lines) { public FancyMessage formattedTooltip(final Iterable<FancyMessage> lines) {
return formattedTooltip(com.boydti.fawe.bukkit.chat.ArrayWrapper.toArray(lines, FancyMessage.class)); return formattedTooltip(
com.boydti.fawe.bukkit.chat.ArrayWrapper.toArray(lines, FancyMessage.class));
} }
/** /**
* If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message. * If the text is a translatable key, and it has replaceable values, this function can be used
* to set the replacements that will be used in the message.
* *
* @param replacements The replacements, in order, that will be used in the language-specific message. * @param replacements The replacements, in order, that will be used in the language-specific
* message.
* @return This builder instance. * @return This builder instance.
*/ */
public FancyMessage translationReplacements(final String... replacements) { public FancyMessage translationReplacements(final String... replacements) {
@ -407,9 +459,11 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
*/ */
/** /**
* If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message. * If the text is a translatable key, and it has replaceable values, this function can be used
* to set the replacements that will be used in the message.
* *
* @param replacements The replacements, in order, that will be used in the language-specific message. * @param replacements The replacements, in order, that will be used in the language-specific
* message.
* @return This builder instance. * @return This builder instance.
*/ */
public FancyMessage translationReplacements(final FancyMessage... replacements) { public FancyMessage translationReplacements(final FancyMessage... replacements) {
@ -421,18 +475,22 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
/** /**
* If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message. * If the text is a translatable key, and it has replaceable values, this function can be used
* to set the replacements that will be used in the message.
* *
* @param replacements The replacements, in order, that will be used in the language-specific message. * @param replacements The replacements, in order, that will be used in the language-specific
* message.
* @return This builder instance. * @return This builder instance.
*/ */
public FancyMessage translationReplacements(final Iterable<FancyMessage> replacements) { public FancyMessage translationReplacements(final Iterable<FancyMessage> replacements) {
return translationReplacements(com.boydti.fawe.bukkit.chat.ArrayWrapper.toArray(replacements, FancyMessage.class)); return translationReplacements(
com.boydti.fawe.bukkit.chat.ArrayWrapper.toArray(replacements, FancyMessage.class));
} }
/** /**
* Terminate construction of the current editing component, and begin construction of a new message component. * Terminate construction of the current editing component, and begin construction of a new
* After a successful call to this method, all setter methods will refer to a new message component, created as a result of the call to this method. * message component. After a successful call to this method, all setter methods will refer to a
* new message component, created as a result of the call to this method.
* *
* @param text The text which will populate the new message component. * @param text The text which will populate the new message component.
* @return This builder instance. * @return This builder instance.
@ -454,8 +512,9 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
/** /**
* Terminate construction of the current editing component, and begin construction of a new message component. * Terminate construction of the current editing component, and begin construction of a new
* After a successful call to this method, all setter methods will refer to a new message component, created as a result of the call to this method. * message component. After a successful call to this method, all setter methods will refer to a
* new message component, created as a result of the call to this method.
* *
* @param text The text which will populate the new message component. * @param text The text which will populate the new message component.
* @return This builder instance. * @return This builder instance.
@ -471,8 +530,9 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
/** /**
* Terminate construction of the current editing component, and begin construction of a new message component. * Terminate construction of the current editing component, and begin construction of a new
* After a successful call to this method, all setter methods will refer to a new message component, created as a result of the call to this method. * message component. After a successful call to this method, all setter methods will refer to a
* new message component, created as a result of the call to this method.
* *
* @return This builder instance. * @return This builder instance.
*/ */
@ -500,8 +560,9 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
/** /**
* Serialize this fancy message, converting it into syntactically-valid JSON using a {@link JsonWriter}. * Serialize this fancy message, converting it into syntactically-valid JSON using a {@link
* This JSON should be compatible with vanilla formatter commands such as {@code /tellraw}. * JsonWriter}. This JSON should be compatible with vanilla formatter commands such as {@code
* /tellraw}.
* *
* @return The JSON string representing this object. * @return The JSON string representing this object.
*/ */
@ -523,7 +584,8 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
/** /**
* Sends this message to a player. The player will receive the fully-fledged formatted display of this message. * Sends this message to a player. The player will receive the fully-fledged formatted display
* of this message.
* *
* @param player The player who will receive the message. * @param player The player who will receive the message.
*/ */
@ -539,8 +601,11 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
Player player = (Player) sender; Player player = (Player) sender;
try { try {
Object handle = Reflection.getHandle(player); Object handle = Reflection.getHandle(player);
Object connection = Reflection.getField(handle.getClass(), "playerConnection").get(handle); Object connection = Reflection.getField(handle.getClass(), "playerConnection")
Reflection.getMethod(connection.getClass(), "sendPacket", Reflection.getNMSClass("Packet")).invoke(connection, createChatPacket(jsonString)); .get(handle);
Reflection
.getMethod(connection.getClass(), "sendPacket", Reflection.getNMSClass("Packet"))
.invoke(connection, createChatPacket(jsonString));
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e); Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e);
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
@ -548,7 +613,8 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} catch (InstantiationException e) { } catch (InstantiationException e) {
Bukkit.getLogger().log(Level.WARNING, "Underlying class is abstract.", e); Bukkit.getLogger().log(Level.WARNING, "Underlying class is abstract.", e);
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e); Bukkit.getLogger()
.log(Level.WARNING, "A error has occurred during invoking of method.", e);
} catch (NoSuchMethodException e) { } catch (NoSuchMethodException e) {
Bukkit.getLogger().log(Level.WARNING, "Could not find method.", e); Bukkit.getLogger().log(Level.WARNING, "Could not find method.", e);
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
@ -560,7 +626,8 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
private static Object nmsChatSerializerGsonInstance; private static Object nmsChatSerializerGsonInstance;
private static Method fromJsonMethod; private static Method fromJsonMethod;
private Object createChatPacket(String json) throws IllegalArgumentException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException { private Object createChatPacket(String json)
throws IllegalArgumentException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException {
if (nmsChatSerializerGsonInstance == null) { if (nmsChatSerializerGsonInstance == null) {
// Find the field and its value, completely bypassing obfuscation // Find the field and its value, completely bypassing obfuscation
Class<?> chatSerializerClazz; Class<?> chatSerializerClazz;
@ -571,7 +638,8 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
// Y = minor // Y = minor
// Z = revision // Z = revision
final String version = Reflection.getVersion(); final String version = Reflection.getVersion();
String[] split = version.substring(1, version.length() - 1).split("_"); // Remove trailing dot String[] split = version.substring(1, version.length() - 1)
.split("_"); // Remove trailing dot
//int majorVersion = Integer.parseInt(split[0]); //int majorVersion = Integer.parseInt(split[0]);
int minorVersion = Integer.parseInt(split[1]); int minorVersion = Integer.parseInt(split[1]);
int revisionVersion = Integer.parseInt(split[2].substring(1)); // Substring to ignore R int revisionVersion = Integer.parseInt(split[2].substring(1)); // Substring to ignore R
@ -587,11 +655,14 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
for (Field declaredField : chatSerializerClazz.getDeclaredFields()) { for (Field declaredField : chatSerializerClazz.getDeclaredFields()) {
if (Modifier.isFinal(declaredField.getModifiers()) && Modifier.isStatic(declaredField.getModifiers()) && declaredField.getType().getName().endsWith("Gson")) { if (Modifier.isFinal(declaredField.getModifiers()) && Modifier
.isStatic(declaredField.getModifiers()) && declaredField.getType().getName()
.endsWith("Gson")) {
// We've found our field // We've found our field
declaredField.setAccessible(true); declaredField.setAccessible(true);
nmsChatSerializerGsonInstance = declaredField.get(null); nmsChatSerializerGsonInstance = declaredField.get(null);
fromJsonMethod = nmsChatSerializerGsonInstance.getClass().getMethod("fromJson", String.class, Class.class); fromJsonMethod = nmsChatSerializerGsonInstance.getClass()
.getMethod("fromJson", String.class, Class.class);
break; break;
} }
} }
@ -599,15 +670,16 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
// Since the method is so simple, and all the obfuscated methods have the same name, it's easier to reimplement 'IChatBaseComponent a(String)' than to reflectively call it // Since the method is so simple, and all the obfuscated methods have the same name, it's easier to reimplement 'IChatBaseComponent a(String)' than to reflectively call it
// Of course, the implementation may change, but fuzzy matches might break with signature changes // Of course, the implementation may change, but fuzzy matches might break with signature changes
Object serializedChatComponent = fromJsonMethod.invoke(nmsChatSerializerGsonInstance, json, Reflection.getNMSClass("IChatBaseComponent")); Object serializedChatComponent = fromJsonMethod.invoke(nmsChatSerializerGsonInstance, json,
Reflection.getNMSClass("IChatBaseComponent"));
return nmsPacketPlayOutChatConstructor.newInstance(serializedChatComponent); return nmsPacketPlayOutChatConstructor.newInstance(serializedChatComponent);
} }
/** /**
* Sends this message to a command sender. * Sends this message to a command sender. If the sender is a player, they will receive the
* If the sender is a player, they will receive the fully-fledged formatted display of this message. * fully-fledged formatted display of this message. Otherwise, they will receive a version of
* Otherwise, they will receive a version of this message with less formatting. * this message with less formatting.
* *
* @param sender The command sender who will receive the message. * @param sender The command sender who will receive the message.
* @see #toOldMessageFormat() * @see #toOldMessageFormat()
@ -630,10 +702,11 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
/** /**
* Convert this message to a human-readable string with limited formatting. * Convert this message to a human-readable string with limited formatting. This method is used
* This method is used to send this message to clients without JSON formatting support. * to send this message to clients without JSON formatting support.
* <p> * <p>
* Serialization of this message by using this message will include (in this order for each message part): * Serialization of this message by using this message will include (in this order for each
* message part):
* <ol> * <ol>
* <li>The color of each message part.</li> * <li>The color of each message part.</li>
* <li>The applicable stylizations for each message part.</li> * <li>The applicable stylizations for each message part.</li>
@ -644,7 +717,8 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
* <p> * <p>
* Color and formatting can be removed from the returned string by using {@link ChatColor#stripColor(String)}.</p> * Color and formatting can be removed from the returned string by using {@link ChatColor#stripColor(String)}.</p>
* *
* @return A human-readable string representing limited formatting in addition to the core text of this message. * @return A human-readable string representing limited formatting in addition to the core text
* of this message.
*/ */
public String toOldMessageFormat() { public String toOldMessageFormat() {
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
@ -669,12 +743,18 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
private void onClick(final String name, final String data) { private void onClick(final String name, final String data) {
onCurrent(m -> { m.clickActionName = name; m.clickActionData = data; }); onCurrent(m -> {
m.clickActionName = name;
m.clickActionData = data;
});
dirty = true; dirty = true;
} }
private void onHover(final String name, final JsonRepresentedObject data) { private void onHover(final String name, final JsonRepresentedObject data) {
onCurrent(m -> { m.hoverActionName = name; m.hoverActionData = data; }); onCurrent(m -> {
m.hoverActionName = name;
m.hoverActionData = data;
});
dirty = true; dirty = true;
} }
@ -687,9 +767,8 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
/** /**
* Deserializes a JSON-represented message from a mapping of key-value pairs. * Deserializes a JSON-represented message from a mapping of key-value pairs. This is called by
* This is called by the Bukkit serialization API. * the Bukkit serialization API. It is not intended for direct public API consumption.
* It is not intended for direct public API consumption.
* *
* @param serialized The key-value mapping which represents a fancy message. * @param serialized The key-value mapping which represents a fancy message.
*/ */
@ -713,8 +792,8 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
private static JsonParser _stringParser = new JsonParser(); private static JsonParser _stringParser = new JsonParser();
/** /**
* Deserializes a fancy message from its JSON representation. This JSON representation is of the format of * Deserializes a fancy message from its JSON representation. This JSON representation is of the
* that returned by {@link #toJSONString()}, and is compatible with vanilla inputs. * format of that returned by {@link #toJSONString()}, and is compatible with vanilla inputs.
* *
* @param json The JSON string which represents a fancy message. * @param json The JSON string which represents a fancy message.
* @return A {@code FancyMessage} representing the parameterized JSON message. * @return A {@code FancyMessage} representing the parameterized JSON message.
@ -738,17 +817,21 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
serializedMapForm.put("value", entry.getValue().getAsString()); serializedMapForm.put("value", entry.getValue().getAsString());
} else { } else {
// Composite object, but we assume each element is a string // Composite object, but we assume each element is a string
for (Map.Entry<String, JsonElement> compositeNestedElement : entry.getValue().getAsJsonObject().entrySet()) { for (Map.Entry<String, JsonElement> compositeNestedElement : entry
serializedMapForm.put("value." + compositeNestedElement.getKey(), compositeNestedElement.getValue().getAsString()); .getValue().getAsJsonObject().entrySet()) {
serializedMapForm.put("value." + compositeNestedElement.getKey(),
compositeNestedElement.getValue().getAsString());
} }
} }
component.text = TextualComponent.deserialize(serializedMapForm); component.text = TextualComponent.deserialize(serializedMapForm);
} else if (MessagePart.stylesToNames.inverse().containsKey(entry.getKey())) { } else if (MessagePart.stylesToNames.inverse().containsKey(entry.getKey())) {
if (entry.getValue().getAsBoolean()) { if (entry.getValue().getAsBoolean()) {
component.styles.add(MessagePart.stylesToNames.inverse().get(entry.getKey())); component.styles
.add(MessagePart.stylesToNames.inverse().get(entry.getKey()));
} }
} else if (entry.getKey().equals("color")) { } else if (entry.getKey().equals("color")) {
component.color = ChatColor.valueOf(entry.getValue().getAsString().toUpperCase()); component.color = ChatColor
.valueOf(entry.getValue().getAsString().toUpperCase());
} else if (entry.getKey().equals("clickEvent")) { } else if (entry.getKey().equals("clickEvent")) {
JsonObject object = entry.getValue().getAsJsonObject(); JsonObject object = entry.getValue().getAsJsonObject();
component.clickActionName = object.get("action").getAsString(); component.clickActionName = object.get("action").getAsString();
@ -758,19 +841,22 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
component.hoverActionName = object.get("action").getAsString(); component.hoverActionName = object.get("action").getAsString();
if (object.get("value").isJsonPrimitive()) { if (object.get("value").isJsonPrimitive()) {
// Assume string // Assume string
component.hoverActionData = new JsonString(object.get("value").getAsString()); component.hoverActionData = new JsonString(
object.get("value").getAsString());
} else { } else {
// Assume composite type // Assume composite type
// The only composite type we currently store is another FancyMessage // The only composite type we currently store is another FancyMessage
// Therefore, recursion time! // Therefore, recursion time!
component.hoverActionData = deserialize(object.get("value").toString() /* This should properly serialize the JSON object as a JSON string */); component.hoverActionData = deserialize(object.get("value")
.toString() /* This should properly serialize the JSON object as a JSON string */);
} }
} else if (entry.getKey().equals("insertion")) { } else if (entry.getKey().equals("insertion")) {
component.insertionData = entry.getValue().getAsString(); component.insertionData = entry.getValue().getAsString();
} else if (entry.getKey().equals("with")) { } else if (entry.getKey().equals("with")) {
for (JsonElement object : entry.getValue().getAsJsonArray()) { for (JsonElement object : entry.getValue().getAsJsonArray()) {
if (object.isJsonPrimitive()) { if (object.isJsonPrimitive()) {
component.translationReplacements.add(new JsonString(object.getAsString())); component.translationReplacements
.add(new JsonString(object.getAsString()));
} else { } else {
// Only composite type stored in this array is - again - FancyMessages // Only composite type stored in this array is - again - FancyMessages
// Recurse within this function to parse this as a translation replacement // Recurse within this function to parse this as a translation replacement

View File

@ -15,7 +15,6 @@ import org.bukkit.World;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.event.Event;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
@ -39,30 +38,31 @@ import org.bukkit.event.entity.ItemSpawnEvent;
import org.bukkit.event.inventory.FurnaceBurnEvent; import org.bukkit.event.inventory.FurnaceBurnEvent;
import org.bukkit.event.inventory.FurnaceSmeltEvent; import org.bukkit.event.inventory.FurnaceSmeltEvent;
import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.plugin.EventExecutor;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import java.lang.reflect.Method;
import java.util.List;
public abstract class ChunkListener implements Listener { public abstract class ChunkListener implements Listener {
protected int rateLimit = 0; protected int rateLimit = 0;
protected Location lastCancelPos; protected Location lastCancelPos;
private int[] badLimit = new int[]{Settings.IMP.TICK_LIMITER.PHYSICS_MS, Settings.IMP.TICK_LIMITER.FALLING, Settings.IMP.TICK_LIMITER.ITEMS}; private int[] badLimit = new int[]{Settings.IMP.TICK_LIMITER.PHYSICS_MS,
Settings.IMP.TICK_LIMITER.FALLING, Settings.IMP.TICK_LIMITER.ITEMS};
public ChunkListener() { public ChunkListener() {
if (Settings.IMP.TICK_LIMITER.ENABLED) { if (Settings.IMP.TICK_LIMITER.ENABLED) {
PluginManager plm = Bukkit.getPluginManager(); PluginManager plm = Bukkit.getPluginManager();
Plugin plugin = Fawe.<FaweBukkit>imp().getPlugin(); Plugin plugin = Fawe.<FaweBukkit>imp().getPlugin();
plm.registerEvents(this, plugin); plm.registerEvents(this, plugin);
try { plm.registerEvents(new ChunkListener_8Plus(this), plugin); } catch (Throwable ignore) {} try {
plm.registerEvents(new ChunkListener_8Plus(this), plugin);
} catch (Throwable ignore) {
}
TaskManager.IMP.repeat(() -> { TaskManager.IMP.repeat(() -> {
Location tmpLoc = lastCancelPos; Location tmpLoc = lastCancelPos;
if (tmpLoc != null) { if (tmpLoc != null) {
Fawe.debug("[FAWE `tick-limiter`] Detected and cancelled physics lag source at " + tmpLoc); Fawe.debug("[FAWE `tick-limiter`] Detected and cancelled physics lag source at "
+ tmpLoc);
} }
rateLimit--; rateLimit--;
physicsFreeze = false; physicsFreeze = false;
@ -86,6 +86,7 @@ public abstract class ChunkListener implements Listener {
} }
protected abstract int getDepth(Exception ex); protected abstract int getDepth(Exception ex);
protected abstract StackTraceElement getElement(Exception ex, int index); protected abstract StackTraceElement getElement(Exception ex, int index);
public static boolean physicsFreeze = false; public static boolean physicsFreeze = false;
@ -105,7 +106,7 @@ public abstract class ChunkListener implements Listener {
long pair = MathMan.pairInt(cx, cz); long pair = MathMan.pairInt(cx, cz);
int[] tmp = lastCount = counter.get(pair); int[] tmp = lastCount = counter.get(pair);
if (tmp == null) { if (tmp == null) {
lastCount = tmp = new int[3]; lastCount = tmp = new int[3];
counter.put(pair, tmp); counter.put(pair, tmp);
} }
return tmp; return tmp;
@ -134,34 +135,54 @@ public abstract class ChunkListener implements Listener {
} }
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void event(BlockBurnEvent event) { reset(); } public void event(BlockBurnEvent event) {
reset();
}
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void event(BlockCanBuildEvent event) { reset(); } public void event(BlockCanBuildEvent event) {
reset();
}
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void event(BlockDamageEvent event) { reset(); } public void event(BlockDamageEvent event) {
reset();
}
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void event(BlockDispenseEvent event) { reset(); } public void event(BlockDispenseEvent event) {
reset();
}
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void event(BlockExpEvent event) { reset(); } public void event(BlockExpEvent event) {
reset();
}
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void event(BlockFadeEvent event) { reset(); } public void event(BlockFadeEvent event) {
reset();
}
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void event(BlockFromToEvent event) { reset(); } public void event(BlockFromToEvent event) {
reset();
}
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void event(BlockGrowEvent event) { reset(); } public void event(BlockGrowEvent event) {
reset();
}
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void event(BlockIgniteEvent event) { reset(); } public void event(BlockIgniteEvent event) {
reset();
}
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void event(BlockPlaceEvent event) { reset(); } public void event(BlockPlaceEvent event) {
reset();
}
// @EventHandler(priority = EventPriority.LOWEST) // @EventHandler(priority = EventPriority.LOWEST)
// public void event(BrewEvent event) { reset(); } // public void event(BrewEvent event) { reset(); }
@ -173,22 +194,34 @@ public abstract class ChunkListener implements Listener {
// public void event(CauldronLevelChangeEvent event ) { reset(); } // public void event(CauldronLevelChangeEvent event ) { reset(); }
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void event(FurnaceBurnEvent event) { reset(); } public void event(FurnaceBurnEvent event) {
reset();
}
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void event(FurnaceSmeltEvent event) { reset(); } public void event(FurnaceSmeltEvent event) {
reset();
}
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void event(LeavesDecayEvent event) { reset(); } public void event(LeavesDecayEvent event) {
reset();
}
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void event(NotePlayEvent event) { reset(); } public void event(NotePlayEvent event) {
reset();
}
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void event(SignChangeEvent event) { reset(); } public void event(SignChangeEvent event) {
reset();
}
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void event(BlockRedstoneEvent event) { reset(); } public void event(BlockRedstoneEvent event) {
reset();
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onPhysics(BlockPhysicsEvent event) { public void onPhysics(BlockPhysicsEvent event) {
@ -209,13 +242,16 @@ public abstract class ChunkListener implements Listener {
return; return;
} }
} else { } else {
if ((++physSkip & 1023) != 0) return; if ((++physSkip & 1023) != 0) {
return;
}
FaweTimer timer = Fawe.get().getTimer(); FaweTimer timer = Fawe.get().getTimer();
if (timer.getTick() != physTick) { if (timer.getTick() != physTick) {
physTick = timer.getTick(); physTick = timer.getTick();
physStart = System.currentTimeMillis(); physStart = System.currentTimeMillis();
return; return;
} else if (System.currentTimeMillis() - physStart < Settings.IMP.TICK_LIMITER.PHYSICS_MS) { } else if (System.currentTimeMillis() - physStart
< Settings.IMP.TICK_LIMITER.PHYSICS_MS) {
return; return;
} }
} }
@ -255,7 +291,8 @@ public abstract class ChunkListener implements Listener {
if (elem != null) { if (elem != null) {
String methodName = elem.getMethodName(); String methodName = elem.getMethodName();
// setAir | setTypeAndData (hacky, but this needs to be efficient) // setAir | setTypeAndData (hacky, but this needs to be efficient)
if (methodName.charAt(0) == 's' && methodName.length() == 6 || methodName.length() == 14) { if (methodName.charAt(0) == 's' && methodName.length() == 6
|| methodName.length() == 14) {
return true; return true;
} }
} }
@ -324,6 +361,7 @@ public abstract class ChunkListener implements Listener {
/** /**
* Prevent FireWorks from loading chunks * Prevent FireWorks from loading chunks
*
* @param event * @param event
*/ */
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
@ -340,16 +378,22 @@ public abstract class ChunkListener implements Listener {
for (int frame = start; frame < depth; frame++) { for (int frame = start; frame < depth; frame++) {
StackTraceElement elem = getElement(e, frame); StackTraceElement elem = getElement(e, frame);
if (elem == null) return; if (elem == null) {
return;
}
String className = elem.getClassName(); String className = elem.getClassName();
int len = className.length(); int len = className.length();
if (len > 15 && className.charAt(len - 15) == 'E' && className.endsWith("EntityFireworks")) { if (len > 15 && className.charAt(len - 15) == 'E' && className
.endsWith("EntityFireworks")) {
for (Entity ent : world.getEntities()) { for (Entity ent : world.getEntities()) {
if (ent.getType() == EntityType.FIREWORK) { if (ent.getType() == EntityType.FIREWORK) {
Vector velocity = ent.getVelocity(); Vector velocity = ent.getVelocity();
double vertical = Math.abs(velocity.getY()); double vertical = Math.abs(velocity.getY());
if (Math.abs(velocity.getX()) > vertical || Math.abs(velocity.getZ()) > vertical) { if (Math.abs(velocity.getX()) > vertical
Fawe.debug("[FAWE `tick-limiter`] Detected and cancelled rogue FireWork at " + ent.getLocation()); || Math.abs(velocity.getZ()) > vertical) {
Fawe.debug(
"[FAWE `tick-limiter`] Detected and cancelled rogue FireWork at "
+ ent.getLocation());
ent.remove(); ent.remove();
} }
} }
@ -378,7 +422,8 @@ public abstract class ChunkListener implements Listener {
cancelNearby(cx, cz); cancelNearby(cx, cz);
if (rateLimit <= 0) { if (rateLimit <= 0) {
rateLimit = 20; rateLimit = 20;
Fawe.debug("[FAWE `tick-limiter`] Detected and cancelled item lag source at " + loc); Fawe.debug(
"[FAWE `tick-limiter`] Detected and cancelled item lag source at " + loc);
} }
event.setCancelled(true); event.setCancelled(true);
return; return;

View File

@ -90,7 +90,7 @@ public class MobSpawnerBlock extends BaseBlock {
/** /**
* Get the spawn delay. * Get the spawn delay.
* *
* @return the delay * @return the delay
*/ */
public short getDelay() { public short getDelay() {
@ -99,13 +99,13 @@ public class MobSpawnerBlock extends BaseBlock {
/** /**
* Set the spawn delay. * Set the spawn delay.
* *
* @param delay the delay to set * @param delay the delay to set
*/ */
public void setDelay(short delay) { public void setDelay(short delay) {
this.delay = delay; this.delay = delay;
} }
@Override @Override
public boolean hasNbtData() { public boolean hasNbtData() {
return true; return true;
@ -208,7 +208,7 @@ public class MobSpawnerBlock extends BaseBlock {
this.spawnCount = spawnCountTag.getValue(); this.spawnCount = spawnCountTag.getValue();
} }
if (spawnRangeTag != null) { if (spawnRangeTag != null) {
this.spawnRange =spawnRangeTag.getValue(); this.spawnRange = spawnRangeTag.getValue();
} }
if (minSpawnDelayTag != null) { if (minSpawnDelayTag != null) {
this.minSpawnDelay = minSpawnDelayTag.getValue(); this.minSpawnDelay = minSpawnDelayTag.getValue();

View File

@ -13,6 +13,7 @@ import java.util.Collection;
import java.util.UUID; import java.util.UUID;
public interface IFawe { public interface IFawe {
void debug(final String s); void debug(final String s);
File getDirectory(); File getDirectory();
@ -31,7 +32,9 @@ public interface IFawe {
void startMetrics(); void startMetrics();
default ImageViewer getImageViewer(FawePlayer player) { return null; } default ImageViewer getImageViewer(FawePlayer player) {
return null;
}
default int getPlayerCount() { default int getPlayerCount() {
return Fawe.get().getCachedPlayers().size(); return Fawe.get().getCachedPlayers().size();

View File

@ -4,7 +4,6 @@ import static com.boydti.fawe.util.image.ImageUtil.load;
import com.boydti.fawe.Fawe; import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweAPI; import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.beta.IQueueExtent;
import com.boydti.fawe.beta.SingleFilterBlock; import com.boydti.fawe.beta.SingleFilterBlock;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Commands; import com.boydti.fawe.config.Commands;
@ -21,17 +20,6 @@ import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.util.TextureUtil; import com.boydti.fawe.util.TextureUtil;
import com.boydti.fawe.util.chat.Message; import com.boydti.fawe.util.chat.Message;
import com.boydti.fawe.util.image.ImageUtil; import com.boydti.fawe.util.image.ImageUtil;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import java.nio.file.Path;
import java.util.function.Consumer;
import java.util.stream.IntStream;
import com.sk89q.worldedit.extension.platform.binding.ProvideBindings;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.exception.StopExecutionException;
import org.enginehub.piston.inject.InjectedValueAccess;
import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.worldedit.EmptyClipboardException; import com.sk89q.worldedit.EmptyClipboardException;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
@ -45,6 +33,7 @@ import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.extension.platform.binding.ProvideBindings;
import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
@ -55,6 +44,7 @@ import com.sk89q.worldedit.registry.state.PropertyKey;
import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.session.request.Request; import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockStateHolder;
@ -67,6 +57,7 @@ import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.nio.file.Path;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayDeque; import java.util.ArrayDeque;
@ -74,6 +65,7 @@ import java.util.Date;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
@ -81,6 +73,7 @@ import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.Switch; import org.enginehub.piston.annotation.param.Switch;
import org.enginehub.piston.exception.StopExecutionException;
import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.InjectedValueAccess;
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) @CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
@ -254,7 +247,7 @@ public class CFICommands extends MethodCommands {
desc = "Set the floor and main block" desc = "Set the floor and main block"
) )
@CommandPermissions("worldedit.anvil.cfi") @CommandPermissions("worldedit.anvil.cfi")
public void column(FawePlayer fp, Pattern pattern, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name='w', desc = "TODO") boolean disableWhiteOnly){ public void column(FawePlayer fp, Pattern pattern, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name = 'w', desc = "TODO") boolean disableWhiteOnly){
HeightMapMCAGenerator gen = assertSettings(fp).getGenerator(); HeightMapMCAGenerator gen = assertSettings(fp).getGenerator();
if (image != null) { if (image != null) {
gen.setColumn(load(image), pattern, !disableWhiteOnly); gen.setColumn(load(image), pattern, !disableWhiteOnly);
@ -273,14 +266,14 @@ public class CFICommands extends MethodCommands {
desc = "Set the floor (default: grass)" desc = "Set the floor (default: grass)"
) )
@CommandPermissions("worldedit.anvil.cfi") @CommandPermissions("worldedit.anvil.cfi")
public void floorCmd(FawePlayer fp, Pattern pattern, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name='w', desc = "TODO") boolean disableWhiteOnly){ public void floorCmd(FawePlayer fp, Pattern pattern, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name = 'w', desc = "TODO") boolean disableWhiteOnly){
floor(fp, pattern, image, mask, disableWhiteOnly); floor(fp, pattern, image, mask, disableWhiteOnly);
fp.sendMessage("Set floor!"); fp.sendMessage("Set floor!");
assertSettings(fp).resetComponent(); assertSettings(fp).resetComponent();
component(fp); component(fp);
} }
private void floor(FawePlayer fp, Pattern pattern, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name='w', desc = "TODO") boolean disableWhiteOnly) { private void floor(FawePlayer fp, Pattern pattern, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name = 'w', desc = "TODO") boolean disableWhiteOnly) {
HeightMapMCAGenerator gen = assertSettings(fp).getGenerator(); HeightMapMCAGenerator gen = assertSettings(fp).getGenerator();
if (image != null) { if (image != null) {
gen.setFloor(load(image), pattern, !disableWhiteOnly); gen.setFloor(load(image), pattern, !disableWhiteOnly);
@ -296,14 +289,14 @@ public class CFICommands extends MethodCommands {
desc = "Set the main block (default: stone)" desc = "Set the main block (default: stone)"
) )
@CommandPermissions("worldedit.anvil.cfi") @CommandPermissions("worldedit.anvil.cfi")
public void mainCmd(FawePlayer fp, Pattern pattern, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name='w', desc = "TODO") boolean disableWhiteOnly){ public void mainCmd(FawePlayer fp, Pattern pattern, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name = 'w', desc = "TODO") boolean disableWhiteOnly){
main(fp, pattern, image, mask, disableWhiteOnly); main(fp, pattern, image, mask, disableWhiteOnly);
fp.sendMessage("Set main!"); fp.sendMessage("Set main!");
assertSettings(fp).resetComponent(); assertSettings(fp).resetComponent();
component(fp); component(fp);
} }
public void main(FawePlayer fp, Pattern pattern, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name='w', desc = "TODO") boolean disableWhiteOnly){ public void main(FawePlayer fp, Pattern pattern, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name = 'w', desc = "TODO") boolean disableWhiteOnly){
HeightMapMCAGenerator gen = assertSettings(fp).getGenerator(); HeightMapMCAGenerator gen = assertSettings(fp).getGenerator();
if (image != null) { if (image != null) {
gen.setMain(load(image), pattern, !disableWhiteOnly); gen.setMain(load(image), pattern, !disableWhiteOnly);
@ -322,7 +315,7 @@ public class CFICommands extends MethodCommands {
"e.g. Tallgrass" "e.g. Tallgrass"
) )
@CommandPermissions("worldedit.anvil.cfi") @CommandPermissions("worldedit.anvil.cfi")
public void overlay(FawePlayer fp, Pattern pattern, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name='w', desc = "TODO") boolean disableWhiteOnly){ public void overlay(FawePlayer fp, Pattern pattern, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name = 'w', desc = "TODO") boolean disableWhiteOnly){
HeightMapMCAGenerator gen = assertSettings(fp).getGenerator(); HeightMapMCAGenerator gen = assertSettings(fp).getGenerator();
if (image != null) { if (image != null) {
gen.setOverlay(load(image), pattern, !disableWhiteOnly); gen.setOverlay(load(image), pattern, !disableWhiteOnly);
@ -344,13 +337,13 @@ public class CFICommands extends MethodCommands {
" - A good value for radius and iterations would be 1 8." " - A good value for radius and iterations would be 1 8."
) )
@CommandPermissions("worldedit.anvil.cfi") @CommandPermissions("worldedit.anvil.cfi")
public void smoothCmd(FawePlayer fp, int radius, int iterations, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name='w', desc = "TODO") boolean disableWhiteOnly){ public void smoothCmd(FawePlayer fp, int radius, int iterations, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name = 'w', desc = "TODO") boolean disableWhiteOnly){
smooth(fp, radius, iterations, image, mask, disableWhiteOnly); smooth(fp, radius, iterations, image, mask, disableWhiteOnly);
assertSettings(fp).resetComponent(); assertSettings(fp).resetComponent();
component(fp); component(fp);
} }
private void smooth(FawePlayer fp, int radius, int iterations, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name='w', desc = "TODO") boolean disableWhiteOnly){ private void smooth(FawePlayer fp, int radius, int iterations, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name = 'w', desc = "TODO") boolean disableWhiteOnly){
HeightMapMCAGenerator gen = assertSettings(fp).getGenerator(); HeightMapMCAGenerator gen = assertSettings(fp).getGenerator();
if (image != null) { if (image != null) {
gen.smooth(load(image), !disableWhiteOnly, radius, iterations); gen.smooth(load(image), !disableWhiteOnly, radius, iterations);
@ -364,7 +357,7 @@ public class CFICommands extends MethodCommands {
desc = "Create some snow" desc = "Create some snow"
) )
@CommandPermissions("worldedit.anvil.cfi") @CommandPermissions("worldedit.anvil.cfi")
public void snow(FawePlayer fp, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name='w', desc = "TODO") boolean disableWhiteOnly){ public void snow(FawePlayer fp, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name = 'w', desc = "TODO") boolean disableWhiteOnly){
HeightMapMCAGenerator gen = assertSettings(fp).getGenerator(); HeightMapMCAGenerator gen = assertSettings(fp).getGenerator();
floor(fp, BlockTypes.SNOW.getDefaultState().with(PropertyKey.LAYERS, 7), image, mask, disableWhiteOnly); floor(fp, BlockTypes.SNOW.getDefaultState().with(PropertyKey.LAYERS, 7), image, mask, disableWhiteOnly);
main(fp, BlockTypes.SNOW_BLOCK, image, mask, disableWhiteOnly); main(fp, BlockTypes.SNOW_BLOCK, image, mask, disableWhiteOnly);
@ -533,7 +526,7 @@ public class CFICommands extends MethodCommands {
" - If a mask is used, the biome will be set anywhere the mask applies" " - If a mask is used, the biome will be set anywhere the mask applies"
) )
@CommandPermissions("worldedit.anvil.cfi") @CommandPermissions("worldedit.anvil.cfi")
public void biome(FawePlayer fp, BiomeType biome, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name='w', desc = "TODO") boolean disableWhiteOnly){ public void biome(FawePlayer fp, BiomeType biome, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name = 'w', desc = "TODO") boolean disableWhiteOnly){
HeightMapMCAGenerator gen = assertSettings(fp).getGenerator(); HeightMapMCAGenerator gen = assertSettings(fp).getGenerator();
if (image != null) { if (image != null) {
gen.setBiome(load(image), biome, !disableWhiteOnly); gen.setBiome(load(image), biome, !disableWhiteOnly);
@ -700,7 +693,7 @@ public class CFICommands extends MethodCommands {
) )
// ![79,174,212,5:3,5:4,18,161,20] // ![79,174,212,5:3,5:4,18,161,20]
@CommandPermissions("worldedit.anvil.cfi") @CommandPermissions("worldedit.anvil.cfi")
public void glass(FawePlayer fp, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri imageMask, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name='w', desc = "TODO") boolean disableWhiteOnly) throws WorldEditException { public void glass(FawePlayer fp, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri imageMask, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name = 'w', desc = "TODO") boolean disableWhiteOnly) throws WorldEditException {
CFISettings settings = assertSettings(fp); CFISettings settings = assertSettings(fp);
settings.getGenerator().setColorWithGlass(load(image)); settings.getGenerator().setColorWithGlass(load(image));
msg("Set color with glass!").send(fp); msg("Set color with glass!").send(fp);
@ -717,7 +710,7 @@ public class CFICommands extends MethodCommands {
"The -w (disableWhiteOnly) will randomly apply depending on the pixel luminance" "The -w (disableWhiteOnly) will randomly apply depending on the pixel luminance"
) )
@CommandPermissions("worldedit.anvil.cfi") @CommandPermissions("worldedit.anvil.cfi")
public void color(FawePlayer fp, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri imageMask, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name='w', desc = "TODO") boolean disableWhiteOnly) throws WorldEditException { public void color(FawePlayer fp, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri imageMask, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name = 'w', desc = "TODO") boolean disableWhiteOnly) throws WorldEditException {
CFISettings settings = assertSettings(fp); CFISettings settings = assertSettings(fp);
HeightMapMCAGenerator gen = settings.getGenerator(); HeightMapMCAGenerator gen = settings.getGenerator();
if (imageMask != null) { if (imageMask != null) {
@ -741,7 +734,7 @@ public class CFICommands extends MethodCommands {
"The -w (disableWhiteOnly) will randomly apply depending on the pixel luminance" "The -w (disableWhiteOnly) will randomly apply depending on the pixel luminance"
) )
@CommandPermissions("worldedit.anvil.cfi") @CommandPermissions("worldedit.anvil.cfi")
public void blockbiome(FawePlayer fp, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri imageMask, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name='w', desc = "TODO") boolean disableWhiteOnly) throws WorldEditException { public void blockbiome(FawePlayer fp, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri imageMask, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name = 'w', desc = "TODO") boolean disableWhiteOnly) throws WorldEditException {
CFISettings settings = assertSettings(fp); CFISettings settings = assertSettings(fp);
settings.getGenerator().setBlockAndBiomeColor(load(image), mask, load(imageMask), !disableWhiteOnly); settings.getGenerator().setBlockAndBiomeColor(load(image), mask, load(imageMask), !disableWhiteOnly);
msg("Set color with blocks and biomes!").send(fp); msg("Set color with blocks and biomes!").send(fp);
@ -757,7 +750,7 @@ public class CFICommands extends MethodCommands {
" - If you changed the block to something other than grass you will not see anything." " - If you changed the block to something other than grass you will not see anything."
) )
@CommandPermissions("worldedit.anvil.cfi") @CommandPermissions("worldedit.anvil.cfi")
public void biomecolor(FawePlayer fp, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri imageMask, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name='w', desc = "TODO") boolean disableWhiteOnly) throws WorldEditException { public void biomecolor(FawePlayer fp, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri image, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri imageMask, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name = 'w', desc = "TODO") boolean disableWhiteOnly) throws WorldEditException {
CFISettings settings = assertSettings(fp); CFISettings settings = assertSettings(fp);
settings.getGenerator().setBiomeColor(load(image)); settings.getGenerator().setBiomeColor(load(image));
msg("Set color with biomes!").send(fp); msg("Set color with biomes!").send(fp);
@ -856,7 +849,7 @@ public class CFICommands extends MethodCommands {
desc = "Select a mask" desc = "Select a mask"
) )
@CommandPermissions("worldedit.anvil.cfi") @CommandPermissions("worldedit.anvil.cfi")
public void mask(FawePlayer fp, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri imageMask, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name='w', desc = "TODO") boolean disableWhiteOnly, InjectedValueAccess context){ public void mask(FawePlayer fp, @Arg(def = "", desc = "image url or filename") ProvideBindings.ImageUri imageMask, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name = 'w', desc = "TODO") boolean disableWhiteOnly, InjectedValueAccess context){
CFISettings settings = assertSettings(fp); CFISettings settings = assertSettings(fp);
String[] split = getArguments(context).split(" "); String[] split = getArguments(context).split(" ");
int index = 2; int index = 2;

View File

@ -4,22 +4,21 @@ import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweAPI; import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings; import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.*; import com.boydti.fawe.object.FaweCommand;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.RegionWrapper;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.object.changeset.DiskStorageHistory; import com.boydti.fawe.object.changeset.DiskStorageHistory;
import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MathMan; import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
public class Rollback extends FaweCommand { public class Rollback extends FaweCommand {
@ -53,9 +52,6 @@ public class Rollback extends FaweCommand {
} }
World world = player.getWorld(); World world = player.getWorld();
switch (args[0]) { switch (args[0]) {
default:
BBC.COMMAND_SYNTAX.send(player, "/frb info u:<uuid> r:<radius> t:<time>");
return false;
case "i": case "i":
case "info": case "info":
if (args.length < 2) { if (args.length < 2) {
@ -117,6 +113,9 @@ public class Rollback extends FaweCommand {
session.flushQueue(); session.flushQueue();
} }
player.sendMessage("Rollback complete!"); player.sendMessage("Rollback complete!");
default:
BBC.COMMAND_SYNTAX.send(player, "/frb info u:<uuid> r:<radius> t:<time>");
return false;
} }
return true; return true;
} }

View File

@ -1,233 +1,234 @@
package com.boydti.fawe.object.collection; package com.boydti.fawe.object.collection;
import javax.annotation.Nonnull;
import java.util.Arrays;
import static it.unimi.dsi.fastutil.HashCommon.arraySize; import static it.unimi.dsi.fastutil.HashCommon.arraySize;
public class ObjObjMap<K, V> import java.util.Arrays;
{ import javax.annotation.Nonnull;
public class ObjObjMap<K, V> {
private static final Object FREE_KEY = new Object(); private static final Object FREE_KEY = new Object();
private static final Object REMOVED_KEY = new Object(); private static final Object REMOVED_KEY = new Object();
/** Keys and values */ /**
* Keys and values
*/
private Object[] m_data; private Object[] m_data;
/** Value for the null key (if inserted into a map) */ /**
* Value for the null key (if inserted into a map)
*/
private Object m_nullValue; private Object m_nullValue;
private boolean m_hasNull; private boolean m_hasNull;
/** Fill factor, must be between (0 and 1) */ /**
* Fill factor, must be between (0 and 1)
*/
private final float m_fillFactor; private final float m_fillFactor;
/** We will resize a map once it reaches this size */ /**
* We will resize a map once it reaches this size
*/
private int m_threshold; private int m_threshold;
/** Current map size */ /**
* Current map size
*/
private int m_size; private int m_size;
/** Mask to calculate the original position */ /**
* Mask to calculate the original position
*/
private int m_mask; private int m_mask;
/** Mask to wrap the actual array pointer */ /**
* Mask to wrap the actual array pointer
*/
private int m_mask2; private int m_mask2;
public ObjObjMap( final int size, final float fillFactor ) public ObjObjMap(int size, float fillFactor) {
{ if (fillFactor <= 0 || fillFactor >= 1) {
if ( fillFactor <= 0 || fillFactor >= 1 ) throw new IllegalArgumentException("FillFactor must be in (0, 1)");
throw new IllegalArgumentException( "FillFactor must be in (0, 1)" ); }
if ( size <= 0 ) if (size <= 0) {
throw new IllegalArgumentException( "Size must be positive!" ); throw new IllegalArgumentException("Size must be positive!");
}
final int capacity = arraySize(size, fillFactor); final int capacity = arraySize(size, fillFactor);
m_mask = capacity - 1; m_mask = capacity - 1;
m_mask2 = capacity * 2 - 1; m_mask2 = capacity * 2 - 1;
m_fillFactor = fillFactor; m_fillFactor = fillFactor;
m_data = new Object[capacity * 2]; m_data = new Object[capacity * 2];
Arrays.fill( m_data, FREE_KEY ); Arrays.fill(m_data, FREE_KEY);
m_threshold = (int) (capacity * fillFactor); m_threshold = (int) (capacity * fillFactor);
} }
public V get( @Nonnull final K key ) public V get(@Nonnull K key) {
{
// if ( key == null ) // if ( key == null )
// return (V) m_nullValue; //we null it on remove, so safe not to check a flag here // return (V) m_nullValue; //we null it on remove, so safe not to check a flag here
int ptr = (key.hashCode() & m_mask) << 1; int ptr = (key.hashCode() & m_mask) << 1;
Object k = m_data[ ptr ]; Object k = m_data[ptr];
// if ( k == FREE_KEY ) // if ( k == FREE_KEY )
// return null; //end of chain already // return null; //end of chain already
if ( k == ( key ) ) //we check FREE and REMOVED prior to this call if (k == key) //we check FREE and REMOVED prior to this call
return (V) m_data[ ptr + 1 ];
while ( true )
{ {
ptr = (ptr + 2) & m_mask2; //that's next index return (V) m_data[ptr + 1];
k = m_data[ ptr ]; }
while (true) {
ptr = ptr + 2 & m_mask2; //that's next index
k = m_data[ptr];
// if ( k == FREE_KEY ) // if ( k == FREE_KEY )
// return null; // return null;
if ( k == ( key ) ) if (k == key) {
return (V) m_data[ ptr + 1 ]; return (V) m_data[ptr + 1];
}
} }
} }
public V put( final K key, final V value ) public V put(K key, V value) {
{ if (key == null) {
if ( key == null )
return insertNullKey(value); return insertNullKey(value);
}
int ptr = getStartIndex(key) << 1; int ptr = getStartIndex(key) << 1;
Object k = m_data[ptr]; Object k = m_data[ptr];
if ( k == FREE_KEY ) //end of chain already if (k == FREE_KEY) {//end of chain already
{ m_data[ptr] = key;
m_data[ ptr ] = key; m_data[ptr + 1] = value;
m_data[ ptr + 1 ] = value; if (m_size >= m_threshold) {
if ( m_size >= m_threshold ) rehash(m_data.length * 2); //size is set inside
rehash( m_data.length * 2 ); //size is set inside } else {
else
++m_size; ++m_size;
}
return null; return null;
} } else if (k == key) { //we check FREE and REMOVED prior to this call
else if ( k == ( key ) ) //we check FREE and REMOVED prior to this call final Object ret = m_data[ptr + 1];
{ m_data[ptr + 1] = value;
final Object ret = m_data[ ptr + 1 ];
m_data[ ptr + 1 ] = value;
return (V) ret; return (V) ret;
} }
int firstRemoved = -1; int firstRemoved = -1;
if ( k == REMOVED_KEY ) if (k == REMOVED_KEY) {
firstRemoved = ptr; //we may find a key later firstRemoved = ptr; //we may find a key later
}
while ( true ) while (true) {
{ ptr = ptr + 2 & m_mask2; //that's next index calculation
ptr = ( ptr + 2 ) & m_mask2; //that's next index calculation k = m_data[ptr];
k = m_data[ ptr ]; if (k == FREE_KEY) {
if ( k == FREE_KEY ) if (firstRemoved != -1) {
{
if ( firstRemoved != -1 )
ptr = firstRemoved; ptr = firstRemoved;
m_data[ ptr ] = key; }
m_data[ ptr + 1 ] = value; m_data[ptr] = key;
if ( m_size >= m_threshold ) m_data[ptr + 1] = value;
rehash( m_data.length * 2 ); //size is set inside if (m_size >= m_threshold) {
else rehash(m_data.length * 2); //size is set inside
} else {
++m_size; ++m_size;
}
return null; return null;
} } else if (k == key) {
else if ( k == ( key ) ) final Object ret = m_data[ptr + 1];
{ m_data[ptr + 1] = value;
final Object ret = m_data[ ptr + 1 ];
m_data[ ptr + 1 ] = value;
return (V) ret; return (V) ret;
} } else if (k == REMOVED_KEY) {
else if ( k == REMOVED_KEY ) if (firstRemoved == -1) {
{
if ( firstRemoved == -1 )
firstRemoved = ptr; firstRemoved = ptr;
}
} }
} }
} }
public V remove( final K key ) public V remove(K key) {
{ if (key == null) {
if ( key == null )
return removeNullKey(); return removeNullKey();
}
int ptr = getStartIndex(key) << 1; int ptr = getStartIndex(key) << 1;
Object k = m_data[ ptr ]; Object k = m_data[ptr];
if ( k == FREE_KEY ) if (k == FREE_KEY) {
return null; //end of chain already return null; //end of chain already
else if ( k == ( key ) ) //we check FREE and REMOVED prior to this call } else if (k == key) { //we check FREE and REMOVED prior to this call
{
--m_size; --m_size;
if ( m_data[ ( ptr + 2 ) & m_mask2 ] == FREE_KEY ) if (m_data[ptr + 2 & m_mask2] == FREE_KEY) {
m_data[ ptr ] = FREE_KEY; m_data[ptr] = FREE_KEY;
else } else {
m_data[ ptr ] = REMOVED_KEY; m_data[ptr] = REMOVED_KEY;
final V ret = (V) m_data[ ptr + 1 ]; }
m_data[ ptr + 1 ] = null; final V ret = (V) m_data[ptr + 1];
m_data[ptr + 1] = null;
return ret; return ret;
} }
while ( true ) while (true) {
{ ptr = ptr + 2 & m_mask2; //that's next index calculation
ptr = ( ptr + 2 ) & m_mask2; //that's next index calculation k = m_data[ptr];
k = m_data[ ptr ]; if (k == FREE_KEY) {
if ( k == FREE_KEY )
return null; return null;
else if ( k == ( key ) ) } else if (k == key) {
{
--m_size; --m_size;
if ( m_data[ ( ptr + 2 ) & m_mask2 ] == FREE_KEY ) if (m_data[ptr + 2 & m_mask2] == FREE_KEY) {
m_data[ ptr ] = FREE_KEY; m_data[ptr] = FREE_KEY;
else } else {
m_data[ ptr ] = REMOVED_KEY; m_data[ptr] = REMOVED_KEY;
final V ret = (V) m_data[ ptr + 1 ]; }
m_data[ ptr + 1 ] = null; final V ret = (V) m_data[ptr + 1];
m_data[ptr + 1] = null;
return ret; return ret;
} }
} }
} }
private V insertNullKey(final V value) private V insertNullKey(V value) {
{ if (m_hasNull) {
if ( m_hasNull )
{
final Object ret = m_nullValue; final Object ret = m_nullValue;
m_nullValue = value; m_nullValue = value;
return (V) ret; return (V) ret;
} } else {
else
{
m_nullValue = value; m_nullValue = value;
++m_size; ++m_size;
return null; return null;
} }
} }
private V removeNullKey() private V removeNullKey() {
{ if (m_hasNull) {
if ( m_hasNull )
{
final Object ret = m_nullValue; final Object ret = m_nullValue;
m_nullValue = null; m_nullValue = null;
m_hasNull = false; m_hasNull = false;
--m_size; --m_size;
return (V) ret; return (V) ret;
} } else {
else
{
return null; return null;
} }
} }
public int size() public int size() {
{
return m_size; return m_size;
} }
private void rehash( final int newCapacity ) private void rehash(int newCapacity) {
{ m_threshold = (int) (newCapacity / 2 * m_fillFactor);
m_threshold = (int) (newCapacity/2 * m_fillFactor); m_mask = newCapacity / 2 - 1;
m_mask = newCapacity/2 - 1;
m_mask2 = newCapacity - 1; m_mask2 = newCapacity - 1;
final int oldCapacity = m_data.length; final int oldCapacity = m_data.length;
final Object[] oldData = m_data; final Object[] oldData = m_data;
m_data = new Object[ newCapacity ]; m_data = new Object[newCapacity];
Arrays.fill( m_data, FREE_KEY ); Arrays.fill(m_data, FREE_KEY);
m_size = m_hasNull ? 1 : 0; m_size = m_hasNull ? 1 : 0;
for ( int i = 0; i < oldCapacity; i += 2 ) { for (int i = 0; i < oldCapacity; i += 2) {
final Object oldKey = oldData[ i ]; final Object oldKey = oldData[i];
if( oldKey != FREE_KEY && oldKey != REMOVED_KEY ) if (oldKey != FREE_KEY && oldKey != REMOVED_KEY) {
put( (K)oldKey, (V)oldData[ i + 1 ]); put((K) oldKey, (V) oldData[i + 1]);
}
} }
} }
public int getStartIndex( final Object key ) public int getStartIndex(Object key) {
{
//key is not null here //key is not null here
return key.hashCode() & m_mask; return key.hashCode() & m_mask;
} }
} }

View File

@ -141,31 +141,28 @@ public class PrimitiveList<T> extends AbstractList<T> {
public void set(int index, char value) { public void set(int index, char value) {
switch (type) { switch (type) {
default:
setFast(index, value);
return;
case Character: case Character:
((char[]) arr)[index] = value; ((char[]) arr)[index] = value;
return; return;
default:
setFast(index, value);
return;
} }
} }
public void set(int index, byte value) { public void set(int index, byte value) {
switch (type) { switch (type) {
default:
setFast(index, value);
return;
case Byte: case Byte:
((byte[]) arr)[index] = value; ((byte[]) arr)[index] = value;
return; return;
default:
setFast(index, value);
return;
} }
} }
public void set(int index, int value) { public void set(int index, int value) {
switch (type) { switch (type) {
default:
setFast(index, value);
return;
case Integer: case Integer:
((int[]) arr)[index] = value; ((int[]) arr)[index] = value;
return; return;
@ -175,14 +172,14 @@ public class PrimitiveList<T> extends AbstractList<T> {
case Double: case Double:
((double[]) arr)[index] = (double) value; ((double[]) arr)[index] = (double) value;
return; return;
default:
setFast(index, value);
return;
} }
} }
public void set(int index, long value) { public void set(int index, long value) {
switch (type) { switch (type) {
default:
setFast(index, value);
return;
case Integer: case Integer:
((int[]) arr)[index] = (int) value; ((int[]) arr)[index] = (int) value;
return; return;
@ -192,14 +189,14 @@ public class PrimitiveList<T> extends AbstractList<T> {
case Double: case Double:
((double[]) arr)[index] = (double) value; ((double[]) arr)[index] = (double) value;
return; return;
default:
setFast(index, value);
return;
} }
} }
public void set(int index, double value) { public void set(int index, double value) {
switch (type) { switch (type) {
default:
setFast(index, value);
return;
case Float: case Float:
((float[]) arr)[index] = (float) value; ((float[]) arr)[index] = (float) value;
return; return;
@ -209,6 +206,9 @@ public class PrimitiveList<T> extends AbstractList<T> {
case Double: case Double:
((double[]) arr)[index] = value; ((double[]) arr)[index] = value;
return; return;
default:
setFast(index, value);
return;
} }
} }

View File

@ -1,6 +1,10 @@
package com.boydti.fawe.object.io; package com.boydti.fawe.object.io;
import java.io.*; import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
/** /**
* A positionable file output stream. * A positionable file output stream.
@ -8,49 +12,50 @@ import java.io.*;
* Threading Design : [x] Single Threaded [ ] Threadsafe [ ] Immutable [ ] Isolated * Threading Design : [x] Single Threaded [ ] Threadsafe [ ] Immutable [ ] Isolated
*/ */
public class RandomFileOutputStream extends OutputStream public class RandomFileOutputStream extends OutputStream {
{
// ***************************************************************************** // *****************************************************************************
// INSTANCE PROPERTIES // INSTANCE PROPERTIES
// ***************************************************************************** // *****************************************************************************
protected RandomAccessFile randomFile; // the random file to write to protected RandomAccessFile randomFile; // the random file to write to
protected boolean sync; // whether to synchronize every write protected boolean sync; // whether to synchronize every write
protected boolean closeParent; protected boolean closeParent;
// ***************************************************************************** // *****************************************************************************
// INSTANCE CONSTRUCTION/INITIALIZATON/FINALIZATION, OPEN/CLOSE // INSTANCE CONSTRUCTION/INITIALIZATON/FINALIZATION, OPEN/CLOSE
// ***************************************************************************** // *****************************************************************************
public RandomFileOutputStream(String fnm) throws IOException { public RandomFileOutputStream(String fnm) throws IOException {
this(fnm,false); this(fnm, false);
} }
public RandomFileOutputStream(String fnm, boolean syn) throws IOException { public RandomFileOutputStream(String fnm, boolean syn) throws IOException {
this(new File(fnm),syn); this(new File(fnm), syn);
} }
public RandomFileOutputStream(File fil) throws IOException { public RandomFileOutputStream(File fil) throws IOException {
this(fil,false); this(fil, false);
} }
public RandomFileOutputStream(File fil, boolean syn) throws IOException { public RandomFileOutputStream(File fil, boolean syn) throws IOException {
super(); super();
File par; // parent file File par; // parent file
fil=fil.getAbsoluteFile(); fil = fil.getAbsoluteFile();
if((par=fil.getParentFile())!=null) { par.mkdirs(); } if ((par = fil.getParentFile()) != null) {
randomFile=new RandomAccessFile(fil,"rw"); par.mkdirs();
sync=syn; }
randomFile = new RandomAccessFile(fil, "rw");
sync = syn;
this.closeParent = true; this.closeParent = true;
} }
public RandomFileOutputStream(RandomAccessFile randomFile, boolean syn, boolean closeParent) { public RandomFileOutputStream(RandomAccessFile randomFile, boolean syn, boolean closeParent) {
super(); super();
this.randomFile = randomFile; this.randomFile = randomFile;
sync=syn; sync = syn;
this.closeParent = closeParent; this.closeParent = closeParent;
} }
@ -58,25 +63,38 @@ public class RandomFileOutputStream extends OutputStream
// INSTANCE METHODS - OUTPUT STREAM IMPLEMENTATION // INSTANCE METHODS - OUTPUT STREAM IMPLEMENTATION
// ***************************************************************************** // *****************************************************************************
@Override
public void write(int val) throws IOException { public void write(int val) throws IOException {
randomFile.write(val); randomFile.write(val);
if(sync) { randomFile.getFD().sync(); } if (sync) {
randomFile.getFD().sync();
}
} }
@Override
public void write(byte[] val) throws IOException { public void write(byte[] val) throws IOException {
randomFile.write(val); randomFile.write(val);
if(sync) { randomFile.getFD().sync(); } if (sync) {
randomFile.getFD().sync();
}
} }
@Override
public void write(byte[] val, int off, int len) throws IOException { public void write(byte[] val, int off, int len) throws IOException {
randomFile.write(val,off,len); randomFile.write(val, off, len);
if(sync) { randomFile.getFD().sync(); } if (sync) {
randomFile.getFD().sync();
}
} }
@Override
public void flush() throws IOException { public void flush() throws IOException {
if(sync) { randomFile.getFD().sync(); } if (sync) {
randomFile.getFD().sync();
}
} }
@Override
public void close() throws IOException { public void close() throws IOException {
if (closeParent) { if (closeParent) {
randomFile.close(); randomFile.close();
@ -107,4 +125,4 @@ public class RandomFileOutputStream extends OutputStream
return randomFile.getFD(); return randomFile.getFD();
} }
} // END PUBLIC CLASS } // END PUBLIC CLASS

View File

@ -1,23 +1,19 @@
package com.boydti.fawe.object.io.zstd; package com.boydti.fawe.object.io.zstd;
public class MalformedInputException public class MalformedInputException extends RuntimeException {
extends RuntimeException
{
private final long offset; private final long offset;
public MalformedInputException(long offset) public MalformedInputException(long offset) {
{
this(offset, "Malformed input"); this(offset, "Malformed input");
} }
public MalformedInputException(long offset, String reason) public MalformedInputException(long offset, String reason) {
{
super(reason + ": offset=" + offset); super(reason + ": offset=" + offset);
this.offset = offset; this.offset = offset;
} }
public long getOffset() public long getOffset() {
{
return offset; return offset;
} }
} }

View File

@ -5,6 +5,7 @@ import java.lang.reflect.Field;
import java.util.Locale; import java.util.Locale;
public class ColorUtil { public class ColorUtil {
private static final int PARSE_COMPONENT = 0; // percent, or clamped to [0,255] => [0,1] private static final int PARSE_COMPONENT = 0; // percent, or clamped to [0,255] => [0,1]
private static final int PARSE_PERCENT = 1; // clamped to [0,100]% => [0,1] private static final int PARSE_PERCENT = 1; // clamped to [0,100]% => [0,1]
private static final int PARSE_ANGLE = 2; // clamped to [0,360] private static final int PARSE_ANGLE = 2; // clamped to [0,360]
@ -17,57 +18,57 @@ public class ColorUtil {
throw new IllegalArgumentException("Invalid color specification"); throw new IllegalArgumentException("Invalid color specification");
} }
type = PARSE_PERCENT; type = PARSE_PERCENT;
color = color.substring(0, color.length()-1).trim(); color = color.substring(0, color.length() - 1).trim();
} else if (type == PARSE_PERCENT) { } else if (type == PARSE_PERCENT) {
throw new IllegalArgumentException("Invalid color specification"); throw new IllegalArgumentException("Invalid color specification");
} }
float c = ((type == PARSE_COMPONENT) float c = type == PARSE_COMPONENT
? Integer.parseInt(color) ? Integer.parseInt(color)
: Float.parseFloat(color)); : Float.parseFloat(color);
switch (type) { switch (type) {
case PARSE_ALPHA: case PARSE_ALPHA:
return (c < 0f) ? 0f : (Math.min(c, 1f)); return c < 0f ? 0f : Math.min(c, 1f);
case PARSE_PERCENT: case PARSE_PERCENT:
return (c <= 0f) ? 0f : ((c >= 100f) ? 1f : (c / 100f)); return c <= 0f ? 0f : c >= 100f ? 1f : c / 100f;
case PARSE_COMPONENT: case PARSE_COMPONENT:
return (c <= 0f) ? 0f : ((c >= 255f) ? 1f : (c / 255f)); return c <= 0f ? 0f : c >= 255f ? 1f : c / 255f;
case PARSE_ANGLE: case PARSE_ANGLE:
return ((c < 0f) return c < 0f
? ((c % 360f) + 360f) ? c % 360f + 360f
: ((c > 360f) : c > 360f
? (c % 360f) ? c % 360f
: c)); : c;
} }
throw new IllegalArgumentException("Invalid color specification"); throw new IllegalArgumentException("Invalid color specification");
} }
private static Color parseRGBColor(String color, int roff) private static Color parseRGBColor(String color, int roff) {
{
try { try {
int rend = color.indexOf(',', roff); int rend = color.indexOf(',', roff);
int gend = rend < 0 ? -1 : color.indexOf(',', rend+1); int gend = rend < 0 ? -1 : color.indexOf(',', rend + 1);
int bend = gend < 0 ? -1 : color.indexOf(gend+1); int bend = gend < 0 ? -1 : color.indexOf(gend + 1);
float r = parseComponent(color, roff, rend, PARSE_COMPONENT); float r = parseComponent(color, roff, rend, PARSE_COMPONENT);
float g = parseComponent(color, rend+1, gend, PARSE_COMPONENT); float g = parseComponent(color, rend + 1, gend, PARSE_COMPONENT);
float b = parseComponent(color, gend+1, bend, PARSE_COMPONENT); float b = parseComponent(color, gend + 1, bend, PARSE_COMPONENT);
return new Color(r, g, b); return new Color(r, g, b);
} catch (NumberFormatException ignored) {} } catch (NumberFormatException ignored) {
}
throw new IllegalArgumentException("Invalid color specification"); throw new IllegalArgumentException("Invalid color specification");
} }
private static Color parseHSLColor(String color, int hoff) private static Color parseHSLColor(String color, int hoff) {
{
try { try {
int hend = color.indexOf(',', hoff); int hend = color.indexOf(',', hoff);
int send = hend < 0 ? -1 : color.indexOf(',', hend+1); int send = hend < 0 ? -1 : color.indexOf(',', hend + 1);
int lend = send < 0 ? -1 : color.indexOf(send+1); int lend = send < 0 ? -1 : color.indexOf(send + 1);
float h = parseComponent(color, hoff, hend, PARSE_ANGLE); float h = parseComponent(color, hoff, hend, PARSE_ANGLE);
float s = parseComponent(color, hend+1, send, PARSE_PERCENT); float s = parseComponent(color, hend + 1, send, PARSE_PERCENT);
float l = parseComponent(color, send+1, lend, PARSE_PERCENT); float l = parseComponent(color, send + 1, lend, PARSE_PERCENT);
return Color.getHSBColor(h, s, l); return Color.getHSBColor(h, s, l);
} catch (NumberFormatException ignored) {} } catch (NumberFormatException ignored) {
}
throw new IllegalArgumentException("Invalid color specification"); throw new IllegalArgumentException("Invalid color specification");
} }
@ -75,7 +76,7 @@ public class ColorUtil {
public static Color parseColor(String colorString) { public static Color parseColor(String colorString) {
if (colorString == null) { if (colorString == null) {
throw new NullPointerException( throw new NullPointerException(
"The color components or name must be specified"); "The color components or name must be specified");
} }
if (colorString.isEmpty()) { if (colorString.isEmpty()) {
throw new IllegalArgumentException("Invalid color specification"); throw new IllegalArgumentException("Invalid color specification");
@ -104,7 +105,8 @@ public class ColorUtil {
try { try {
Field field = Color.class.getField(color.toLowerCase()); Field field = Color.class.getField(color.toLowerCase());
col = (Color) field.get(null); col = (Color) field.get(null);
} catch (Throwable ignore) {} } catch (Throwable ignore) {
}
if (col != null) { if (col != null) {
return col; return col;
} }
@ -138,7 +140,8 @@ public class ColorUtil {
b = Integer.parseInt(color.substring(4, 6), 16); b = Integer.parseInt(color.substring(4, 6), 16);
return new Color(r, g, b); return new Color(r, g, b);
} }
} catch (NumberFormatException ignored) {} } catch (NumberFormatException ignored) {
}
throw new IllegalArgumentException("Invalid color specification"); throw new IllegalArgumentException("Invalid color specification");
} }

View File

@ -30,14 +30,14 @@ public class MaskTraverser {
Field field = current.getDeclaredField("extent"); Field field = current.getDeclaredField("extent");
field.setAccessible(true); field.setAccessible(true);
field.set(mask, newExtent); field.set(mask, newExtent);
} catch (NoSuchFieldException | IllegalAccessException ignore) { } catch (NoSuchFieldException | IllegalAccessException ignored) {
} }
try { try {
Field field = current.getDeclaredField("mask"); Field field = current.getDeclaredField("mask");
field.setAccessible(true); field.setAccessible(true);
Mask next = (Mask) field.get(mask); Mask next = (Mask) field.get(mask);
reset(next, newExtent); reset(next, newExtent);
} catch (NoSuchFieldException | IllegalAccessException ignore) { } catch (NoSuchFieldException | IllegalAccessException ignored) {
} }
try { try {
Field field = current.getDeclaredField("masks"); Field field = current.getDeclaredField("masks");
@ -46,7 +46,7 @@ public class MaskTraverser {
for (Mask next : masks) { for (Mask next : masks) {
reset(next, newExtent); reset(next, newExtent);
} }
} catch (NoSuchFieldException | IllegalAccessException ignore) { } catch (NoSuchFieldException | IllegalAccessException ignored) {
} }
current = current.getSuperclass(); current = current.getSuperclass();
} }

View File

@ -1,6 +1,7 @@
package com.boydti.fawe.util.image; package com.boydti.fawe.util.image;
import com.boydti.fawe.Fawe; import com.boydti.fawe.Fawe;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MathMan; import com.boydti.fawe.util.MathMan;
import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.InputParseException;
@ -21,17 +22,17 @@ import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
public class ImageUtil { public class ImageUtil {
public static BufferedImage getScaledInstance(BufferedImage img, public static BufferedImage getScaledInstance(BufferedImage img,
int targetWidth, int targetWidth,
int targetHeight, int targetHeight,
Object hint, Object hint,
boolean higherQuality) boolean higherQuality) {
{
if (img.getHeight() == targetHeight && img.getWidth() == targetWidth) { if (img.getHeight() == targetHeight && img.getWidth() == targetWidth) {
return img; return img;
} }
int type = (img.getTransparency() == Transparency.OPAQUE) ? int type = img.getTransparency() == Transparency.OPAQUE ?
BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB; BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = img; BufferedImage ret = img;
int w, h; int w, h;
if (higherQuality) { if (higherQuality) {
@ -53,21 +54,27 @@ public class ImageUtil {
if (w < targetWidth) { if (w < targetWidth) {
w = targetWidth; w = targetWidth;
} }
} else if (w < targetWidth) w = targetWidth; } else if (w < targetWidth) {
w = targetWidth;
}
if (higherQuality && h > targetHeight) { if (higherQuality && h > targetHeight) {
h /= 2; h /= 2;
if (h < targetHeight) { if (h < targetHeight) {
h = targetHeight; h = targetHeight;
} }
} else if (h < targetHeight) h = targetHeight; } else if (h < targetHeight) {
h = targetHeight;
}
BufferedImage tmp = new BufferedImage(w, h, type); BufferedImage tmp = new BufferedImage(w, h, type);
Graphics2D g2 = tmp.createGraphics(); Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint); g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED); g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
g2.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_SPEED); g2.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
g2.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED); RenderingHints.VALUE_COLOR_RENDER_SPEED);
g2.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED);
g2.drawImage(ret, 0, 0, w, h, null); g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose(); g2.dispose();
@ -103,12 +110,13 @@ public class ImageUtil {
float dz2 = sqrZ[z]; float dz2 = sqrZ[z];
for (int x = 0; x < width; x++, index++) { for (int x = 0; x < width; x++, index++) {
int color = raw[index]; int color = raw[index];
int alpha = (color >> 24) & 0xFF; int alpha = color >> 24 & 0xFF;
if (alpha != 0) { if (alpha != 0) {
float dx2 = sqrX[x]; float dx2 = sqrX[x];
float distSqr = dz2 + dx2; float distSqr = dz2 + dx2;
if (distSqr > 1) raw[index] = 0; if (distSqr > 1) {
else { raw[index] = 0;
} else {
alpha = (int) (alpha * (1 - distSqr)); alpha = (int) (alpha * (1 - distSqr));
raw[index] = (color & 0x00FFFFFF) + (alpha << 24); raw[index] = (color & 0x00FFFFFF) + (alpha << 24);
} }
@ -119,10 +127,10 @@ public class ImageUtil {
public static void scaleAlpha(BufferedImage image, double alphaScale) { public static void scaleAlpha(BufferedImage image, double alphaScale) {
int[] raw = ((DataBufferInt) image.getRaster().getDataBuffer()).getData(); int[] raw = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
int defined = (MathMan.clamp((int) (255 * alphaScale), 0, 255)) << 24; int defined = MathMan.clamp((int) (255 * alphaScale), 0, 255) << 24;
for (int i = 0; i < raw.length; i++) { for (int i = 0; i < raw.length; i++) {
int color = raw[i]; int color = raw[i];
int alpha = ((color >> 24) & 0xFF); int alpha = color >> 24 & 0xFF;
switch (alpha) { switch (alpha) {
case 0: case 0:
continue; continue;
@ -147,10 +155,10 @@ public class ImageUtil {
for (int x = 0; x < width; x++) { for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) { for (int y = 0; y < height; y++) {
int color = image.getRGB(x, y); int color = image.getRGB(x, y);
totalRed += (color >> 16) & 0xFF; totalRed += color >> 16 & 0xFF;
totalGreen += (color >> 8) & 0xFF; totalGreen += color >> 8 & 0xFF;
totalBlue += (color >> 0) & 0xFF; totalBlue += color >> 0 & 0xFF;
totalAlpha += (color >> 24) & 0xFF; totalAlpha += color >> 24 & 0xFF;
} }
} }
int a = width * height; int a = width * height;
@ -161,7 +169,8 @@ public class ImageUtil {
return (alpha << 24) + (red << 16) + (green << 8) + (blue << 0); return (alpha << 24) + (red << 16) + (green << 8) + (blue << 0);
} }
public static BufferedImage load(@Nullable ProvideBindings.ImageUri uri) throws InputParseException { public static BufferedImage load(@Nullable ProvideBindings.ImageUri uri)
throws InputParseException {
return uri == null ? null : uri.load(); return uri == null ? null : uri.load();
} }
@ -200,7 +209,8 @@ public class ImageUtil {
return img; return img;
} else if (arg.startsWith("file:/")) { } else if (arg.startsWith("file:/")) {
arg = arg.replaceFirst("file:/+", ""); arg = arg.replaceFirst("file:/+", "");
File file = MainUtil.getFile(MainUtil.getFile(Fawe.imp().getDirectory(), com.boydti.fawe.config.Settings.IMP.PATHS.HEIGHTMAP), arg); File file = MainUtil.getFile(MainUtil.getFile(Fawe.imp().getDirectory(),
Settings.IMP.PATHS.HEIGHTMAP), arg);
return MainUtil.readImage(file); return MainUtil.readImage(file);
} else { } else {
throw new InputParseException("Invalid image " + arg); throw new InputParseException("Invalid image " + arg);
@ -219,7 +229,8 @@ public class ImageUtil {
return new URL(arg).toURI(); return new URL(arg).toURI();
} else if (arg.startsWith("file:/")) { } else if (arg.startsWith("file:/")) {
arg = arg.replaceFirst("file:/+", ""); arg = arg.replaceFirst("file:/+", "");
File file = MainUtil.getFile(MainUtil.getFile(Fawe.imp().getDirectory(), com.boydti.fawe.config.Settings.IMP.PATHS.HEIGHTMAP), arg); File file = MainUtil.getFile(MainUtil.getFile(Fawe.imp().getDirectory(),
Settings.IMP.PATHS.HEIGHTMAP), arg);
if (!file.exists()) { if (!file.exists()) {
throw new InputParseException("File not found " + file); throw new InputParseException("File not found " + file);
} }

View File

@ -66,60 +66,57 @@ public class SchemSync implements Runnable {
byte[] header = new byte[32]; byte[] header = new byte[32];
try (ServerSocket serverSocket = this.serverSocket = new ServerSocket(PORT)) { try (ServerSocket serverSocket = this.serverSocket = new ServerSocket(PORT)) {
while (!Thread.interrupted()) { while (!Thread.interrupted()) {
try { try (Socket clientSocket = this.clientSocket = serverSocket
try (Socket clientSocket = this.clientSocket = serverSocket.accept()) { .accept(); InputStream in = clientSocket.getInputStream()) {
try (InputStream in = clientSocket.getInputStream()) { int read = in.read(header);
int read = in.read(header); if (read != header.length) {
if (read != header.length) { close(Error.INVALID_HEADER_LENGTH);
close(Error.INVALID_HEADER_LENGTH); }
}
ByteBuffer buf = ByteBuffer.wrap(header); ByteBuffer buf = ByteBuffer.wrap(header);
UUID uuid = new UUID(buf.getLong(), buf.getLong()); UUID uuid = new UUID(buf.getLong(), buf.getLong());
UUID expectedToken = tokens.get(uuid); UUID expectedToken = tokens.get(uuid);
if (expectedToken == null) { if (expectedToken == null) {
close(Error.TOKEN_REJECTED); close(Error.TOKEN_REJECTED);
} }
UUID receivedToken = new UUID(buf.getLong(), buf.getLong()); UUID receivedToken = new UUID(buf.getLong(), buf.getLong());
if (!receivedToken.equals(expectedToken)) { if (!receivedToken.equals(expectedToken)) {
continue; continue;
} }
try (DataInputStream dis = new DataInputStream(in)) { try (DataInputStream dis = new DataInputStream(in)) {
File dir = new File(working, uuid.toString()); File dir = new File(working, uuid.toString());
int data = dis.readByte() & 0xFF; int data = dis.readByte() & 0xFF;
switch (data) { switch (data) {
case 0: // list case 0: // list
try (DataOutputStream out = new DataOutputStream( try (DataOutputStream out = new DataOutputStream(
clientSocket.getOutputStream())) { clientSocket.getOutputStream())) {
out.write(1); out.write(1);
UtilityCommands.allFiles(dir.listFiles(), true, UtilityCommands.allFiles(dir.listFiles(), true,
file -> { file -> {
try { try {
String path = dir.toURI() String path = dir.toURI()
.relativize(file.toURI()).getPath(); .relativize(file.toURI()).getPath();
out.writeUTF(path); out.writeUTF(path);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
}); });
}
break;
case 1: // get
String input = dis.readUTF();
File file = new File(dir, input);
if (!MainUtil.isInSubDirectory(dir, file)) {
close(Error.NO_FILE_PERMISSIONS);
}
if (!file.exists()) {
close(Error.FILE_NOT_EXIST);
}
// todo send file
} }
} break;
case 1: // get
String input = dis.readUTF();
File file = new File(dir, input);
if (!MainUtil.isInSubDirectory(dir, file)) {
close(Error.NO_FILE_PERMISSIONS);
}
if (!file.exists()) {
close(Error.FILE_NOT_EXIST);
}
// todo send file
} }
} }
} catch (FaweException ignore) { } catch (FaweException ignore) {

View File

@ -190,7 +190,7 @@ public abstract class LocalConfiguration {
data = Byte.parseByte(splitter[1]); data = Byte.parseByte(splitter[1]);
} }
item = LegacyMapper.getInstance().getItemFromLegacy(id, data).getId(); item = LegacyMapper.getInstance().getItemFromLegacy(id, data).getId();
} catch (Throwable e) { } catch (Throwable ignored) {
} }
return item; return item;

View File

@ -204,7 +204,7 @@ public class BrushCommands extends MethodCommands {
public BrushSettings recursiveBrush(Player player, LocalSession session, EditSession editSession, Pattern fill, public BrushSettings recursiveBrush(Player player, LocalSession session, EditSession editSession, Pattern fill,
@Arg(desc = "The radius to sample for blending", def = "5") @Arg(desc = "The radius to sample for blending", def = "5")
Expression radius, Expression radius,
@Switch(name='d', desc = "Apply in depth first order") @Switch(name = 'd', desc = "Apply in depth first order")
boolean depthFirst, boolean depthFirst,
InjectedValueAccess context) throws WorldEditException { InjectedValueAccess context) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius); worldEdit.checkMaxBrushRadius(radius);
@ -224,11 +224,11 @@ public class BrushCommands extends MethodCommands {
public BrushSettings lineBrush(Player player, LocalSession session, Pattern fill, public BrushSettings lineBrush(Player player, LocalSession session, Pattern fill,
@Arg(desc = "The radius to sample for blending", def = "0") @Arg(desc = "The radius to sample for blending", def = "0")
Expression radius, Expression radius,
@Switch(name='h', desc = "Create only a shell") @Switch(name = 'h', desc = "Create only a shell")
boolean shell, boolean shell,
@Switch(name='s', desc = "Selects the clicked point after drawing") @Switch(name = 's', desc = "Selects the clicked point after drawing")
boolean select, boolean select,
@Switch(name='f', desc = "Create a flat line") @Switch(name = 'f', desc = "Create a flat line")
boolean flat, InjectedValueAccess context) throws WorldEditException { boolean flat, InjectedValueAccess context) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius); worldEdit.checkMaxBrushRadius(radius);
return set(session, context, return set(session, context,
@ -279,14 +279,14 @@ public class BrushCommands extends MethodCommands {
desc = "Create a hanging line between two points" desc = "Create a hanging line between two points"
) )
@CommandPermissions("worldedit.brush.spline") @CommandPermissions("worldedit.brush.spline")
public BrushSettings catenaryBrush(LocalSession session, Pattern fill, @Arg(def = "1.2", desc = "Length of wire compared to distance between points") @Range(min=1) double lengthFactor, public BrushSettings catenaryBrush(LocalSession session, Pattern fill, @Arg(def = "1.2", desc = "Length of wire compared to distance between points") @Range(min = 1) double lengthFactor,
@Arg(desc = "The radius to sample for blending", def = "0") @Arg(desc = "The radius to sample for blending", def = "0")
Expression radius, Expression radius,
@Switch(name='h', desc = "Create only a shell") @Switch(name = 'h', desc = "Create only a shell")
boolean shell, boolean shell,
@Switch(name='s', desc = "Select the clicked point after drawing") @Switch(name = 's', desc = "Select the clicked point after drawing")
boolean select, boolean select,
@Switch(name='d', desc = "sags the catenary toward the facing direction") @Switch(name = 'd', desc = "sags the catenary toward the facing direction")
boolean facingDirection, boolean facingDirection,
InjectedValueAccess context) throws WorldEditException { InjectedValueAccess context) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius); worldEdit.checkMaxBrushRadius(radius);
@ -403,10 +403,10 @@ public class BrushCommands extends MethodCommands {
public BrushSettings stencilBrush(Player player, LocalSession session, Pattern fill, public BrushSettings stencilBrush(Player player, LocalSession session, Pattern fill,
@Arg(name = "radius", desc = "Expression", def = "5") Expression radius, @Arg(name = "radius", desc = "Expression", def = "5") Expression radius,
@Arg(name = "image", desc = "String", def = "") String image, @Arg(name = "image", desc = "String", def = "") String image,
@Arg(def = "0", desc = "rotation") @Range(min=0, max=360) int rotation, @Arg(def = "0", desc = "rotation") @Range(min = 0, max = 360) int rotation,
@Arg(name = "yscale", desc = "double", def = "1") double yscale, @Arg(name = "yscale", desc = "double", def = "1") double yscale,
@Switch(name='w', desc = "Apply at maximum saturation") boolean onlyWhite, @Switch(name = 'w', desc = "Apply at maximum saturation") boolean onlyWhite,
@Switch(name='r', desc = "Apply random rotation") boolean randomRotate, @Switch(name = 'r', desc = "Apply random rotation") boolean randomRotate,
InjectedValueAccess context) throws WorldEditException, FileNotFoundException { InjectedValueAccess context) throws WorldEditException, FileNotFoundException {
worldEdit.checkMaxBrushRadius(radius); worldEdit.checkMaxBrushRadius(radius);
InputStream stream = getHeightmapStream(image); InputStream stream = getHeightmapStream(image);
@ -433,9 +433,9 @@ public class BrushCommands extends MethodCommands {
@CommandPermissions("worldedit.brush.stencil") @CommandPermissions("worldedit.brush.stencil")
public BrushSettings imageBrush(LocalSession session, @Arg(name = "radius", desc = "Expression", def = "5") Expression radius, public BrushSettings imageBrush(LocalSession session, @Arg(name = "radius", desc = "Expression", def = "5") Expression radius,
ProvideBindings.ImageUri imageUri, ProvideBindings.ImageUri imageUri,
@Arg(def = "1", desc = "scale height") @Range(min=Double.MIN_NORMAL) double yscale, @Arg(def = "1", desc = "scale height") @Range(min = Double.MIN_NORMAL) double yscale,
@Switch(name='a', desc = "Use image Alpha") boolean alpha, @Switch(name = 'a', desc = "Use image Alpha") boolean alpha,
@Switch(name='f', desc = "Blend the image with existing terrain") boolean fadeOut, @Switch(name = 'f', desc = "Blend the image with existing terrain") boolean fadeOut,
InjectedValueAccess context) throws WorldEditException, IOException { InjectedValueAccess context) throws WorldEditException, IOException {
BufferedImage image = imageUri.load(); BufferedImage image = imageUri.load();
worldEdit.checkMaxBrushRadius(radius); worldEdit.checkMaxBrushRadius(radius);
@ -460,7 +460,7 @@ public class BrushCommands extends MethodCommands {
descFooter = "Use a height map to paint any surface.\n" + descFooter = "Use a height map to paint any surface.\n" +
"The -w flag will only apply at maximum saturation\n" + "The -w flag will only apply at maximum saturation\n" +
"The -r flag will apply random rotation" "The -r flag will apply random rotation"
) )
@CommandPermissions("worldedit.brush.surface") @CommandPermissions("worldedit.brush.surface")
public BrushSettings surfaceBrush(LocalSession session, Pattern fill, public BrushSettings surfaceBrush(LocalSession session, Pattern fill,
@Arg(name = "radius", desc = "Expression", def = "5") @Arg(name = "radius", desc = "Expression", def = "5")
@ -474,11 +474,10 @@ public class BrushCommands extends MethodCommands {
name = "scatter", name = "scatter",
desc = "Scatter a pattern on a surface", desc = "Scatter a pattern on a surface",
descFooter = "Set a number of blocks randomly on a surface each a certain distance apart.\n" + descFooter = "Set a number of blocks randomly on a surface each a certain distance apart.\n" +
" The -o flag will overlay the block\n" +
"Video: https://youtu.be/RPZIaTbqoZw?t=34s" "Video: https://youtu.be/RPZIaTbqoZw?t=34s"
) )
@CommandPermissions("worldedit.brush.scatter") @CommandPermissions("worldedit.brush.scatter")
public BrushSettings scatterBrush(LocalSession session, Pattern fill, @Arg(name = "radius", desc = "Expression", def = "5") Expression radius, @Arg(name = "points", desc = "double", def = "5") double points, @Arg(name = "distance", desc = "double", def = "1") double distance, @Switch(name='o', desc = "TODO") boolean overlay, InjectedValueAccess context) throws WorldEditException { public BrushSettings scatterBrush(LocalSession session, Pattern fill, @Arg(name = "radius", desc = "Expression", def = "5") Expression radius, @Arg(name = "points", desc = "double", def = "5") double points, @Arg(name = "distance", desc = "double", def = "1") double distance, @Switch(name = 'o', desc = "Overlay the block") boolean overlay, InjectedValueAccess context) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius); worldEdit.checkMaxBrushRadius(radius);
Brush brush; Brush brush;
if (overlay) { if (overlay) {
@ -495,12 +494,10 @@ public class BrushCommands extends MethodCommands {
@Command( @Command(
name = "populateschematic", name = "populateschematic",
aliases = {"populateschem", "popschem", "pschem", "ps"}, aliases = {"populateschem", "popschem", "pschem", "ps"},
desc = "Scatter a schematic on a surface", desc = "Scatter a schematic on a surface"
descFooter = "Chooses the scatter schematic brush.\n" +
"The -r flag will apply random rotation"
) )
@CommandPermissions("worldedit.brush.populateschematic") @CommandPermissions("worldedit.brush.populateschematic")
public BrushSettings scatterSchemBrush(Player player, LocalSession session, Mask mask, String clipboard, @Arg(name = "radius", desc = "Expression", def = "30") Expression radius, @Arg(name = "density", desc = "double", def = "50") double density, @Switch(name='r', desc = "TODO") boolean rotate, InjectedValueAccess context) throws WorldEditException { public BrushSettings scatterSchemBrush(Player player, LocalSession session, Mask mask, String clipboard, @Arg(name = "radius", desc = "Expression", def = "30") Expression radius, @Arg(name = "density", desc = "double", def = "50") double density, @Switch(name = 'r', desc = "Apply random rotation") boolean rotate, InjectedValueAccess context) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius); worldEdit.checkMaxBrushRadius(radius);
try { try {
MultiClipboardHolder clipboards = ClipboardFormats.loadAllFromInput(player, clipboard, null, true); MultiClipboardHolder clipboards = ClipboardFormats.loadAllFromInput(player, clipboard, null, true);
@ -704,7 +701,7 @@ public class BrushCommands extends MethodCommands {
"Snow Pic: https://i.imgur.com/Hrzn0I4.png" "Snow Pic: https://i.imgur.com/Hrzn0I4.png"
) )
@CommandPermissions("worldedit.brush.height") @CommandPermissions("worldedit.brush.height")
public BrushSettings heightBrush(Player player, LocalSession session, @Arg(name = "radius", desc = "Expression", def = "5") Expression radius, @Arg(name = "image", desc = "String", def = "") String image, @Arg(def = "0", desc = "rotation") @Range(min=0, max=360) int rotation, @Arg(name = "yscale", desc = "double", def = "1") double yscale, @Switch(name='r', desc = "TODO") boolean randomRotate, @Switch(name='l', desc = "TODO") boolean layers, @Switch(name='s', desc = "TODO") boolean dontSmooth, InjectedValueAccess context) throws WorldEditException, FileNotFoundException { public BrushSettings heightBrush(Player player, LocalSession session, @Arg(name = "radius", desc = "Expression", def = "5") Expression radius, @Arg(name = "image", desc = "String", def = "") String image, @Arg(def = "0", desc = "rotation") @Range(min = 0, max = 360) int rotation, @Arg(name = "yscale", desc = "double", def = "1") double yscale, @Switch(name = 'r', desc = "TODO") boolean randomRotate, @Switch(name = 'l', desc = "TODO") boolean layers, @Switch(name = 's', desc = "TODO") boolean dontSmooth, InjectedValueAccess context) throws WorldEditException, FileNotFoundException {
return terrainBrush(player, session, radius, image, rotation, yscale, false, randomRotate, layers, !dontSmooth, ScalableHeightMap.Shape.CONE, context); return terrainBrush(player, session, radius, image, rotation, yscale, false, randomRotate, layers, !dontSmooth, ScalableHeightMap.Shape.CONE, context);
} }
@ -712,13 +709,24 @@ public class BrushCommands extends MethodCommands {
name = "cliff", name = "cliff",
aliases = {"flatcylinder"}, aliases = {"flatcylinder"},
desc = "Cliff brush", desc = "Cliff brush",
descFooter = "This brush flattens terrain and creates cliffs.\n" + descFooter = "This brush flattens terrain and creates cliffs."
" - The `-r` flag enables random off-axis rotation\n" +
" - The `-l` flag will work on snow layers\n" +
" - The `-s` flag disables smoothing"
) )
@CommandPermissions("worldedit.brush.height") @CommandPermissions("worldedit.brush.height")
public BrushSettings cliffBrush(Player player, LocalSession session, @Arg(name = "radius", desc = "Expression", def = "5") Expression radius, @Arg(name = "image", desc = "String", def = "") String image, @Arg(def = "0", desc = "rotation") @Step(90) @Range(min=0, max=360) int rotation, @Arg(name = "yscale", desc = "double", def = "1") double yscale, @Switch(name='r', desc = "TODO") boolean randomRotate, @Switch(name='l', desc = "TODO") boolean layers, @Switch(name='s', desc = "TODO") boolean dontSmooth, InjectedValueAccess context) throws WorldEditException, FileNotFoundException { public BrushSettings cliffBrush(Player player, LocalSession session,
@Arg(name = "radius", desc = "Expression", def = "5")
Expression radius,
@Arg(name = "image", desc = "String", def = "")
String image,
@Arg(def = "0", desc = "rotation") @Step(90) @Range(min = 0, max = 360)
int rotation,
@Arg(name = "yscale", desc = "double", def = "1")
double yscale,
@Switch(name = 'r', desc = "Enables random off-axis rotation")
boolean randomRotate,
@Switch(name = 'l', desc = "Will work on snow layers")
boolean layers,
@Switch(name = 's', desc = "Disables smoothing")
boolean dontSmooth, InjectedValueAccess context) throws WorldEditException, FileNotFoundException {
return terrainBrush(player, session, radius, image, rotation, yscale, true, randomRotate, layers, !dontSmooth, ScalableHeightMap.Shape.CYLINDER, context); return terrainBrush(player, session, radius, image, rotation, yscale, true, randomRotate, layers, !dontSmooth, ScalableHeightMap.Shape.CYLINDER, context);
} }
@ -728,12 +736,12 @@ public class BrushCommands extends MethodCommands {
desc = "This brush raises or lowers land towards the clicked point" desc = "This brush raises or lowers land towards the clicked point"
) )
@CommandPermissions("worldedit.brush.height") @CommandPermissions("worldedit.brush.height")
public BrushSettings flattenBrush(Player player, LocalSession session, @Arg(name = "radius", desc = "Expression", def = "5") Expression radius, @Arg(name = "image", desc = "String", def = "") String image, @Arg(def = "0", desc = "rotation") @Step(90) @Range(min=0, max=360) int rotation, @Arg(name = "yscale", desc = "double", def = "1") double yscale, public BrushSettings flattenBrush(Player player, LocalSession session, @Arg(name = "radius", desc = "Expression", def = "5") Expression radius, @Arg(name = "image", desc = "String", def = "") String image, @Arg(def = "0", desc = "rotation") @Step(90) @Range(min = 0, max = 360) int rotation, @Arg(name = "yscale", desc = "double", def = "1") double yscale,
@Switch(name='r', desc = "Enables random off-axis rotation") @Switch(name = 'r', desc = "Enables random off-axis rotation")
boolean randomRotate, boolean randomRotate,
@Switch(name='l', desc = "Will work on snow layers") @Switch(name = 'l', desc = "Will work on snow layers")
boolean layers, boolean layers,
@Switch(name='s', desc = "Disables smoothing") @Switch(name = 's', desc = "Disables smoothing")
boolean dontSmooth, InjectedValueAccess context) throws WorldEditException, FileNotFoundException { boolean dontSmooth, InjectedValueAccess context) throws WorldEditException, FileNotFoundException {
return terrainBrush(player, session, radius, image, rotation, yscale, true, randomRotate, layers, !dontSmooth, ScalableHeightMap.Shape.CONE, context); return terrainBrush(player, session, radius, image, rotation, yscale, true, randomRotate, layers, !dontSmooth, ScalableHeightMap.Shape.CONE, context);
} }
@ -783,7 +791,7 @@ public class BrushCommands extends MethodCommands {
"Video: https://www.youtube.com/watch?v=RPZIaTbqoZw" "Video: https://www.youtube.com/watch?v=RPZIaTbqoZw"
) )
@CommandPermissions("worldedit.brush.copy") @CommandPermissions("worldedit.brush.copy")
public BrushSettings copy(Player player, LocalSession session, @Arg(name = "radius", desc = "Expression", def = "5") Expression radius, @Switch(name='r', desc = "Apply random rotation on paste") boolean randomRotate, @Switch(name='a', desc = "Apply auto view based rotation on paste") boolean autoRotate, InjectedValueAccess context) throws WorldEditException { public BrushSettings copy(Player player, LocalSession session, @Arg(name = "radius", desc = "Expression", def = "5") Expression radius, @Switch(name = 'r', desc = "Apply random rotation on paste") boolean randomRotate, @Switch(name = 'a', desc = "Apply auto view based rotation on paste") boolean autoRotate, InjectedValueAccess context) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius); worldEdit.checkMaxBrushRadius(radius);
player.print(BBC.BRUSH_COPY.f(radius)); player.print(BBC.BRUSH_COPY.f(radius));

View File

@ -13,43 +13,38 @@ import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MathMan; import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.StringMan; import com.boydti.fawe.util.StringMan;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.sk89q.worldedit.command.argument.Arguments;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.internal.command.CommandArgParser;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.inject.InjectedValueAccess;
import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.command.argument.Arguments;
import com.sk89q.worldedit.command.tool.BrushTool; import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.platform.CommandEvent; import com.sk89q.worldedit.event.platform.CommandEvent;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.PlatformCommandManager; import com.sk89q.worldedit.extension.platform.PlatformCommandManager;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.util.HandSide;
import com.sk89q.worldedit.internal.annotation.Range; import com.sk89q.worldedit.internal.annotation.Range;
import org.enginehub.piston.annotation.param.Arg; import com.sk89q.worldedit.internal.command.CommandArgParser;
import org.enginehub.piston.annotation.param.Switch; import com.sk89q.worldedit.util.HandSide;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.File; import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.file.FileSystems; import java.nio.file.FileSystems;
import java.util.List; import java.util.List;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.Switch;
import org.enginehub.piston.inject.InjectedValueAccess;
/** /**
* Tool commands. * Tool commands.
@ -317,7 +312,7 @@ public class BrushOptionsCommands {
public void scroll(Player player, EditSession editSession, LocalSession session, public void scroll(Player player, EditSession editSession, LocalSession session,
@Switch(name = 'h', desc = "TODO") @Switch(name = 'h', desc = "TODO")
boolean offHand, boolean offHand,
@Arg(desc="Target Modes") @Arg(desc = "Target Modes")
String modes, String modes,
@Arg(desc = "The scroll action", variable = true) @Arg(desc = "The scroll action", variable = true)
List<String> command) throws WorldEditException { List<String> command) throws WorldEditException {

View File

@ -19,6 +19,11 @@
package com.sk89q.worldedit.command; package com.sk89q.worldedit.command;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL;
import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT;
import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION;
import com.boydti.fawe.Fawe; import com.boydti.fawe.Fawe;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.FawePlayer;
@ -26,11 +31,6 @@ import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MathMan; import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.TextureUtil; import com.boydti.fawe.util.TextureUtil;
import com.boydti.fawe.util.image.ImageUtil; import com.boydti.fawe.util.image.ImageUtil;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldedit.function.generator.CavesGen;
import org.enginehub.piston.inject.InjectedValueAccess;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
@ -38,16 +38,14 @@ import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.Logging;
import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL;
import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT;
import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.function.generator.CavesGen;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.visitor.RegionVisitor; import com.sk89q.worldedit.function.visitor.RegionVisitor;
import com.sk89q.worldedit.internal.annotation.Range;
import com.sk89q.worldedit.internal.annotation.Selection; import com.sk89q.worldedit.internal.annotation.Selection;
import static com.sk89q.worldedit.internal.command.CommandUtil.checkCommandArgument;
import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
@ -55,19 +53,18 @@ import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.util.TreeGenerator.TreeType;
import com.sk89q.worldedit.internal.annotation.Range;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockType;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.Switch;
import java.util.List;
import java.awt.RenderingHints; import java.awt.RenderingHints;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.List;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.Switch;
import org.enginehub.piston.inject.InjectedValueAccess;
/** /**
* Commands for the generation of shapes and other objects. * Commands for the generation of shapes and other objects.
@ -278,7 +275,7 @@ public class GenerationCommands extends MethodCommands {
int size, int size,
@Arg(desc = "The type of forest", def = "tree") @Arg(desc = "The type of forest", def = "tree")
TreeType type, TreeType type,
@Range(min=0, max = 100) @Arg(desc = "The density of the forest, between 0 and 100", def = "5") @Range(min = 0, max = 100) @Arg(desc = "The density of the forest, between 0 and 100", def = "5")
double density) throws WorldEditException { double density) throws WorldEditException {
density = density / 100; density = density / 100;
int affected = editSession.makeForest(session.getPlacementPosition(player), size, density, type); int affected = editSession.makeForest(session.getPlacementPosition(player), size, density, type);
@ -297,7 +294,7 @@ public class GenerationCommands extends MethodCommands {
int size, int size,
@Arg(desc = "//TODO", def = "10") @Arg(desc = "//TODO", def = "10")
int apothem, int apothem,
@Range(min=0, max = 100) @Arg(desc = "//TODO ", def = "0.02") @Range(min = 0, max = 100) @Arg(desc = "//TODO ", def = "0.02")
double density) throws WorldEditException { double density) throws WorldEditException {
int affected = editSession.makePumpkinPatches(session.getPlacementPosition(player), apothem, density); int affected = editSession.makePumpkinPatches(session.getPlacementPosition(player), apothem, density);
BBC.COMMAND_PUMPKIN.send(player, affected); BBC.COMMAND_PUMPKIN.send(player, affected);
@ -409,7 +406,6 @@ public class GenerationCommands extends MethodCommands {
name = "/generatebiome", name = "/generatebiome",
aliases = { "/genbiome", "/gb" }, aliases = { "/genbiome", "/gb" },
desc = "Sets biome according to a formula.", desc = "Sets biome according to a formula.",
descFooter = "Formula must return positive numbers (true) if the point is inside the shape\n" + descFooter = "Formula must return positive numbers (true) if the point is inside the shape\n" +
"Sets the biome of blocks in that shape.\n" "Sets the biome of blocks in that shape.\n"
+"See also https://tinyurl.com/weexpr." +"See also https://tinyurl.com/weexpr."

View File

@ -82,7 +82,7 @@ public class HistoryCommands extends MethodCommands {
" - Import from disk: /frb #import" " - Import from disk: /frb #import"
) )
@CommandPermissions("worldedit.history.rollback") @CommandPermissions("worldedit.history.rollback")
public void faweRollback(Player player, LocalSession session, String user, @Arg(def = "0", desc = "radius") @Range(min = 0) int radius, @Arg(name = "time", desc = "String", def = "0") String time, @Switch(name='r', desc = "TODO") boolean restore) throws WorldEditException { public void faweRollback(Player player, LocalSession session, String user, @Arg(def = "0", desc = "radius") @Range(min = 0) int radius, @Arg(name = "time", desc = "String", def = "0") String time, @Switch(name = 'r', desc = "TODO") boolean restore) throws WorldEditException {
if (!Settings.IMP.HISTORY.USE_DATABASE) { if (!Settings.IMP.HISTORY.USE_DATABASE) {
BBC.SETTING_DISABLE.send(player, "history.use-database (Import with /frb #import )"); BBC.SETTING_DISABLE.send(player, "history.use-database (Import with /frb #import )");
return; return;

View File

@ -282,7 +282,7 @@ public class MaskCommands extends MethodCommands {
"Example: /[3][20]\n" + "Example: /[3][20]\n" +
"Explanation: Allows any block where the adjacent block is between 3 and 20 blocks below" "Explanation: Allows any block where the adjacent block is between 3 and 20 blocks below"
) )
public Mask angle(Extent extent, String min, String max, @Switch(name='o', desc = "TODO") boolean overlay, @Arg(name = "distance", desc = "int", def = "1") int distance) throws ExpressionException { public Mask angle(Extent extent, String min, String max, @Switch(name = 'o', desc = "TODO") boolean overlay, @Arg(name = "distance", desc = "int", def = "1") int distance) throws ExpressionException {
double y1, y2; double y1, y2;
boolean override; boolean override;
if (max.endsWith("d")) { if (max.endsWith("d")) {
@ -307,7 +307,7 @@ public class MaskCommands extends MethodCommands {
"Explanation: Restrict near where the angle changes between 0-45 degrees within 5 blocks\n" + "Explanation: Restrict near where the angle changes between 0-45 degrees within 5 blocks\n" +
"Note: Use negatives for decreasing slope" "Note: Use negatives for decreasing slope"
) )
public Mask roc(Extent extent, String min, String max, @Switch(name='o', desc = "TODO") boolean overlay, @Arg(name = "distance", desc = "int", def = "4") int distance) throws ExpressionException { public Mask roc(Extent extent, String min, String max, @Switch(name = 'o', desc = "TODO") boolean overlay, @Arg(name = "distance", desc = "int", def = "4") int distance) throws ExpressionException {
double y1, y2; double y1, y2;
boolean override; boolean override;
if (max.endsWith("d")) { if (max.endsWith("d")) {
@ -332,7 +332,7 @@ public class MaskCommands extends MethodCommands {
"Explanation: Restrict to near 45 degrees of local maxima\n" + "Explanation: Restrict to near 45 degrees of local maxima\n" +
"Note: Use negatives for local minima" "Note: Use negatives for local minima"
) )
public Mask extrema(Extent extent, String min, String max, @Switch(name='o', desc = "TODO") boolean overlay, @Arg(name = "distance", desc = "int", def = "4") int distance) throws ExpressionException { public Mask extrema(Extent extent, String min, String max, @Switch(name = 'o', desc = "TODO") boolean overlay, @Arg(name = "distance", desc = "int", def = "4") int distance) throws ExpressionException {
double y1, y2; double y1, y2;
boolean override; boolean override;
if (max.endsWith("d")) { if (max.endsWith("d")) {

View File

@ -19,6 +19,15 @@
package com.sk89q.worldedit.command; package com.sk89q.worldedit.command;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL;
import static com.sk89q.worldedit.command.util.Logging.LogMode.ORIENTATION_REGION;
import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
import static com.sk89q.worldedit.internal.command.CommandUtil.checkCommandArgument;
import static com.sk89q.worldedit.regions.Regions.asFlatRegion;
import static com.sk89q.worldedit.regions.Regions.maximumBlockY;
import static com.sk89q.worldedit.regions.Regions.minimumBlockY;
import com.boydti.fawe.FaweAPI; import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.FaweLimit; import com.boydti.fawe.object.FaweLimit;
@ -62,25 +71,15 @@ import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.util.TreeGenerator.TreeType;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockStateHolder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.Switch; import org.enginehub.piston.annotation.param.Switch;
import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.InjectedValueAccess;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL;
import static com.sk89q.worldedit.command.util.Logging.LogMode.ORIENTATION_REGION;
import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
import static com.sk89q.worldedit.internal.command.CommandUtil.checkCommandArgument;
import static com.sk89q.worldedit.regions.Regions.asFlatRegion;
import static com.sk89q.worldedit.regions.Regions.maximumBlockY;
import static com.sk89q.worldedit.regions.Regions.minimumBlockY;
/** /**
* Commands that operate on regions. * Commands that operate on regions.
*/ */
@ -404,7 +403,7 @@ public class RegionCommands extends MethodCommands {
int iterations, int iterations,
@Arg(desc = "The mask of blocks to use as the height map", def = "") @Arg(desc = "The mask of blocks to use as the height map", def = "")
Mask mask, Mask mask,
@Switch(name='s', desc = "TODO") boolean snow, InjectedValueAccess context) throws WorldEditException { @Switch(name = 's', desc = "TODO") boolean snow, InjectedValueAccess context) throws WorldEditException {
BlockVector3 min = region.getMinimumPoint(); BlockVector3 min = region.getMinimumPoint();
BlockVector3 max = region.getMaximumPoint(); BlockVector3 max = region.getMaximumPoint();
long volume = (((long) max.getX() - (long) min.getX() + 1) * ((long) max.getY() - (long) min.getY() + 1) * ((long) max.getZ() - (long) min.getZ() + 1)); long volume = (((long) max.getX() - (long) min.getX() + 1) * ((long) max.getY() - (long) min.getY() + 1) * ((long) max.getZ() - (long) min.getZ() + 1));
@ -483,11 +482,11 @@ public class RegionCommands extends MethodCommands {
boolean moveSelection, boolean moveSelection,
@Switch(name = 'a', desc = "Ignore air blocks") @Switch(name = 'a', desc = "Ignore air blocks")
boolean ignoreAirBlocks, boolean ignoreAirBlocks,
@Switch(name='b', desc = "TODO") @Switch(name = 'b', desc = "TODO")
boolean copyBiomes, boolean copyBiomes,
@Switch(name='e', desc = "TODO") @Switch(name = 'e', desc = "TODO")
boolean skipEntities, boolean skipEntities,
@Switch(name='a', desc = "TODO") @Switch(name = 'a', desc = "TODO")
boolean skipAir, boolean skipAir,
InjectedValueAccess context) throws WorldEditException { InjectedValueAccess context) throws WorldEditException {
checkCommandArgument(count >= 1, "Count must be >= 1"); checkCommandArgument(count >= 1, "Count must be >= 1");
@ -520,7 +519,7 @@ public class RegionCommands extends MethodCommands {
public void fall(FawePlayer player, EditSession editSession, LocalSession session, public void fall(FawePlayer player, EditSession editSession, LocalSession session,
@Selection Region region, @Selection Region region,
@Arg(name = "replace", desc = "BlockStateHolder", def = "air") BlockStateHolder replace, @Arg(name = "replace", desc = "BlockStateHolder", def = "air") BlockStateHolder replace,
@Switch(name='m', desc = "TODO") boolean notFullHeight, @Switch(name = 'm', desc = "TODO") boolean notFullHeight,
InjectedValueAccess context) throws WorldEditException { InjectedValueAccess context) throws WorldEditException {
player.checkConfirmationRegion(() -> { player.checkConfirmationRegion(() -> {
int affected = editSession.fall(region, !notFullHeight, replace); int affected = editSession.fall(region, !notFullHeight, replace);
@ -547,7 +546,7 @@ public class RegionCommands extends MethodCommands {
@Switch(name = 'e', desc = "//TODO") boolean skipEntities, @Switch(name = 'e', desc = "//TODO") boolean skipEntities,
@Switch(name = 'a', desc = "Ignore air blocks") @Switch(name = 'a', desc = "Ignore air blocks")
boolean ignoreAirBlocks, boolean ignoreAirBlocks,
@Switch(name='m', desc = "TODO") Mask sourceMask, InjectedValueAccess context) throws WorldEditException { @Switch(name = 'm', desc = "TODO") Mask sourceMask, InjectedValueAccess context) throws WorldEditException {
player.checkConfirmationStack(() -> { player.checkConfirmationStack(() -> {
if (sourceMask != null) { if (sourceMask != null) {
editSession.addSourceMask(sourceMask); editSession.addSourceMask(sourceMask);
@ -674,7 +673,7 @@ public class RegionCommands extends MethodCommands {
@Range(min = 0) int thickness, @Range(min = 0) int thickness,
@Arg(desc = "The pattern of blocks to replace the hollowed area with", def = "air") @Arg(desc = "The pattern of blocks to replace the hollowed area with", def = "air")
Pattern pattern, Pattern pattern,
@Switch(name='m', desc = "Mask to hollow with") Mask mask, @Switch(name = 'm', desc = "Mask to hollow with") Mask mask,
InjectedValueAccess context) throws WorldEditException { InjectedValueAccess context) throws WorldEditException {
Mask finalMask = mask == null ? new SolidBlockMask(editSession) : mask; Mask finalMask = mask == null ? new SolidBlockMask(editSession) : mask;
player.checkConfirmationRegion(() -> { player.checkConfirmationRegion(() -> {

View File

@ -35,19 +35,23 @@ import com.boydti.fawe.object.schematic.StructureFormat;
import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.chat.Message; import com.boydti.fawe.util.chat.Message;
import com.sk89q.worldedit.command.util.AsyncCommandBuilder;
import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.InjectedValueAccess;
import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.util.AsyncCommandBuilder;
import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.extent.PlayerSaveClipboardEvent; import com.sk89q.worldedit.event.extent.PlayerSaveClipboardEvent;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
@ -55,6 +59,7 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.formatting.component.CodeFormat;
import com.sk89q.worldedit.util.formatting.component.ErrorFormat; import com.sk89q.worldedit.util.formatting.component.ErrorFormat;
import com.sk89q.worldedit.util.formatting.component.PaginationBox; import com.sk89q.worldedit.util.formatting.component.PaginationBox;
import com.sk89q.worldedit.util.formatting.component.SchematicPaginationBox; import com.sk89q.worldedit.util.formatting.component.SchematicPaginationBox;
@ -116,17 +121,15 @@ public class SchematicCommands {
@Command( @Command(
name = "loadall", name = "loadall",
desc = "Load multiple clipboards (paste will randomly choose one)", desc = "Load multiple clipboards (paste will randomly choose one)"
descFooter = "Load multiple clipboards (paste will randomly choose one)\n" +
"The -r flag will apply random rotation"
) )
@Deprecated @Deprecated
@CommandPermissions({"worldedit.clipboard.load", "worldedit.schematic.load", "worldedit.schematic.load.web", "worldedit.schematic.load.asset"}) @CommandPermissions({"worldedit.clipboard.load", "worldedit.schematic.load", "worldedit.schematic.load.web", "worldedit.schematic.load.asset"})
public void loadall(final Player player, final LocalSession session, public void loadall(Player player, LocalSession session,
@Arg(desc = "Format name.", def = "schematic") @Arg(desc = "Format name.", def = "schematic")
final String formatName, String formatName,
@Arg(desc = "File name.") @Arg(desc = "File name.")
final String filename, String filename,
@Switch(name = 'r', desc = "Apply random rotation") @Switch(name = 'r', desc = "Apply random rotation")
boolean randomRotate) throws FilenameException { boolean randomRotate) throws FilenameException {
final ClipboardFormat format = ClipboardFormats.findByAlias(formatName); final ClipboardFormat format = ClipboardFormats.findByAlias(formatName);
@ -195,7 +198,7 @@ public class SchematicCommands {
) )
@Deprecated @Deprecated
@CommandPermissions({"worldedit.schematic.remap"}) @CommandPermissions({"worldedit.schematic.remap"})
public void remap(final Player player, final LocalSession session) throws WorldEditException { public void remap(Player player, LocalSession session) throws WorldEditException {
ClipboardRemapper remapper = new ClipboardRemapper(ClipboardRemapper.RemapPlatform.PE, ClipboardRemapper.RemapPlatform.PC); ClipboardRemapper remapper = new ClipboardRemapper(ClipboardRemapper.RemapPlatform.PE, ClipboardRemapper.RemapPlatform.PC);
for (Clipboard clip : session.getClipboard().getClipboards()) { for (Clipboard clip : session.getClipboard().getClipboards()) {
@ -251,7 +254,7 @@ public class SchematicCommands {
return; return;
} }
} else { } else {
if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}").matcher(filename).find() && !player.hasPermission("worldedit.schematic.load.other")) { if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && !player.hasPermission("worldedit.schematic.load.other") && Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}").matcher(filename).find()) {
BBC.NO_PERM.send(player, "worldedit.schematic.load.other"); BBC.NO_PERM.send(player, "worldedit.schematic.load.other");
return; return;
} }
@ -359,16 +362,6 @@ public class SchematicCommands {
} }
} }
if (f.getName().replaceAll("." + format.getPrimaryFileExtension(), "").isEmpty()) {
File directory = f.getParentFile();
if (directory.exists()) {
int max = MainUtil.getMaxFileId(directory);
f = new File(directory, max + "." + format.getPrimaryFileExtension());
} else {
f = new File(directory, "1." + format.getPrimaryFileExtension());
}
}
// Create parent directories // Create parent directories
File parent = f.getParentFile(); File parent = f.getParentFile();
if (parent != null && !parent.exists()) { if (parent != null && !parent.exists()) {
@ -377,55 +370,16 @@ public class SchematicCommands {
"Could not create folder for schematics!")); "Could not create folder for schematics!"));
} }
} }
try {
if (!f.exists()) {
f.createNewFile();
} else if (!allowOverwrite) {
BBC.SCHEMATIC_MOVE_EXISTS.send(player, f.getName());
}
try (FileOutputStream fos = new FileOutputStream(f)) { ClipboardHolder holder = session.getClipboard();
ClipboardHolder holder = session.getClipboard();
Clipboard clipboard = holder.getClipboard();
Transform transform = holder.getTransform();
Clipboard target;
// If we have a transform, bake it into the copy SchematicSaveTask task = new SchematicSaveTask(player, f, format, holder, overwrite);
if (!transform.isIdentity()) { AsyncCommandBuilder.wrap(task, player)
FlattenedClipboardTransform result = FlattenedClipboardTransform.transform(clipboard, transform); .registerWithSupervisor(worldEdit.getSupervisor(), "Saving schematic " + filename)
target = new BlockArrayClipboard(result.getTransformedRegion(), UUID.randomUUID()); .sendMessageAfterDelay("(Please wait... saving schematic.)")
target.setOrigin(clipboard.getOrigin()); .onSuccess(filename + " saved" + (overwrite ? " (overwriting previous file)." : "."), null)
Operations.completeLegacy(result.copyTo(target)); .onFailure("Failed to load schematic", worldEdit.getPlatformManager().getPlatformCommandManager().getExceptionConverter())
} else { .buildAndExec(worldEdit.getExecutorService());
target = clipboard;
}
URI uri = null;
if (holder instanceof URIClipboardHolder) {
uri = ((URIClipboardHolder) holder).getURI(clipboard);
}
if (new PlayerSaveClipboardEvent(player, clipboard, uri, f.toURI()).call()) {
try (ClipboardWriter writer = format.getWriter(fos)) {
if (writer instanceof MinecraftStructure) {
((MinecraftStructure) writer).write(target, player.getName());
} else {
writer.write(target);
}
log.info(player.getName() + " saved " + f.getCanonicalPath());
BBC.SCHEMATIC_SAVED.send(player, filename);
}
} else {
BBC.WORLDEDIT_CANCEL_REASON_MANUAL.send(player);
}
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
player.printError("Unknown filename: " + filename);
} catch (IOException e) {
e.printStackTrace();
player.printError("Schematic could not written: " + e.getMessage());
log.warn("Failed to write a saved clipboard", e);
}
} }
@Command( @Command(
@ -505,7 +459,8 @@ public class SchematicCommands {
} }
for (File f : files) { for (File f : files) {
if (!MainUtil.isInSubDirectory(working, f) || !f.exists()) { if (!MainUtil.isInSubDirectory(working, f) || !f.exists()) {
actor.printError("Schematic " + filename + " does not exist! (" + f.exists() + "|" + f + "|" + (!MainUtil.isInSubDirectory(working, f)) + ")"); actor.printError("Schematic " + filename + " does not exist! (" + f.exists() + "|" + f + "|" + !MainUtil.isInSubDirectory(working, f)
+ ")");
continue; continue;
} }
if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && !MainUtil.isInSubDirectory(dir, f) && !actor.hasPermission("worldedit.schematic.delete.other")) { if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && !MainUtil.isInSubDirectory(dir, f) && !actor.hasPermission("worldedit.schematic.delete.other")) {
@ -753,9 +708,21 @@ public class SchematicCommands {
FileOutputStream fos = closer.register(new FileOutputStream(file)); FileOutputStream fos = closer.register(new FileOutputStream(file));
BufferedOutputStream bos = closer.register(new BufferedOutputStream(fos)); BufferedOutputStream bos = closer.register(new BufferedOutputStream(fos));
ClipboardWriter writer = closer.register(format.getWriter(bos)); ClipboardWriter writer = closer.register(format.getWriter(bos));
writer.write(target); URI uri = null;
if (holder instanceof URIClipboardHolder) {
log.info(player.getName() + " saved " + file.getCanonicalPath() + (overwrite ? " (overwriting previous file)" : "")); uri = ((URIClipboardHolder) holder).getURI(clipboard);
}
if (new PlayerSaveClipboardEvent(player, clipboard, uri, file.toURI()).call()) {
if (writer instanceof MinecraftStructure) {
((MinecraftStructure) writer).write(target, player.getName());
} else {
writer.write(target);
}
log.info(player.getName() + " saved " + file.getCanonicalPath());
BBC.SCHEMATIC_SAVED.send(player, file.getName());
} else {
BBC.WORLDEDIT_CANCEL_REASON_MANUAL.send(player);
}
} }
return null; return null;
} }

View File

@ -188,11 +188,14 @@ public class UtilityCommands {
@Arg(desc = "The blocks to fill with") @Arg(desc = "The blocks to fill with")
Pattern pattern, Pattern pattern,
@Arg(desc = "The radius to fill in") @Arg(desc = "The radius to fill in")
@Range(min=1) double radius, double radius,
@Arg(desc = "The depth to fill", def = "1") @Arg(desc = "The depth to fill", def = "1")
@Range(min=1) int depth, int depth,
@Arg(desc = "Direction to fill", def = "down") BlockVector3 direction) throws WorldEditException { @Arg(desc = "Direction to fill", def = "down")
BlockVector3 direction) throws WorldEditException {
radius = Math.max(1, radius);
we.checkMaxRadius(radius); we.checkMaxRadius(radius);
depth = Math.max(1, depth);
BlockVector3 pos = session.getPlacementPosition(player); BlockVector3 pos = session.getPlacementPosition(player);
int affected = editSession.fillDirection(pos, pattern, radius, depth, direction); int affected = editSession.fillDirection(pos, pattern, radius, depth, direction);
@ -281,9 +284,10 @@ public class UtilityCommands {
@Arg(desc = "The blocks to fill with") @Arg(desc = "The blocks to fill with")
Pattern pattern, Pattern pattern,
@Arg(desc = "The radius to fill in") @Arg(desc = "The radius to fill in")
@Range(min=1) double radius, double radius,
@Arg(desc = "The depth to fill", def = "") @Arg(desc = "The depth to fill", def = "")
@Range(min=1) Integer depth) throws WorldEditException { Integer depth) throws WorldEditException {
radius = Math.max(1, radius);
we.checkMaxRadius(radius); we.checkMaxRadius(radius);
depth = depth == null ? Integer.MAX_VALUE : Math.max(1, depth); depth = depth == null ? Integer.MAX_VALUE : Math.max(1, depth);
we.checkMaxRadius(radius); we.checkMaxRadius(radius);
@ -302,9 +306,10 @@ public class UtilityCommands {
@Logging(PLACEMENT) @Logging(PLACEMENT)
public int drain(Player player, LocalSession session, EditSession editSession, public int drain(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The radius to drain") @Arg(desc = "The radius to drain")
@Range(min=0) double radius, double radius,
@Switch(name = 'w', desc = "Also un-waterlog blocks") @Switch(name = 'w', desc = "Also un-waterlog blocks")
boolean waterlogged) throws WorldEditException { boolean waterlogged) throws WorldEditException {
radius = Math.max(0, radius);
we.checkMaxRadius(radius); we.checkMaxRadius(radius);
int affected = editSession.drainArea( int affected = editSession.drainArea(
session.getPlacementPosition(player), radius, waterlogged); session.getPlacementPosition(player), radius, waterlogged);
@ -321,7 +326,8 @@ public class UtilityCommands {
@Logging(PLACEMENT) @Logging(PLACEMENT)
public int fixLava(Player player, LocalSession session, EditSession editSession, public int fixLava(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The radius to fix in") @Arg(desc = "The radius to fix in")
@Range(min=0) double radius) throws WorldEditException { double radius) throws WorldEditException {
radius = Math.max(0, radius);
we.checkMaxRadius(radius); we.checkMaxRadius(radius);
int affected = editSession.fixLiquid(session.getPlacementPosition(player), radius, BlockTypes.LAVA); int affected = editSession.fixLiquid(session.getPlacementPosition(player), radius, BlockTypes.LAVA);
player.print(affected + " block(s) have been changed."); player.print(affected + " block(s) have been changed.");
@ -337,7 +343,8 @@ public class UtilityCommands {
@Logging(PLACEMENT) @Logging(PLACEMENT)
public int fixWater(Player player, LocalSession session, EditSession editSession, public int fixWater(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The radius to fix in") @Arg(desc = "The radius to fix in")
@Range(min=0) double radius) throws WorldEditException { double radius) throws WorldEditException {
radius = Math.max(0, radius);
we.checkMaxRadius(radius); we.checkMaxRadius(radius);
int affected = editSession.fixLiquid(session.getPlacementPosition(player), radius, BlockTypes.WATER); int affected = editSession.fixLiquid(session.getPlacementPosition(player), radius, BlockTypes.WATER);
BBC.VISITOR_BLOCK.send(player, affected); BBC.VISITOR_BLOCK.send(player, affected);
@ -353,10 +360,14 @@ public class UtilityCommands {
@Logging(PLACEMENT) @Logging(PLACEMENT)
public int removeAbove(Player player, LocalSession session, EditSession editSession, public int removeAbove(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The apothem of the square to remove from", def = "1") @Arg(desc = "The apothem of the square to remove from", def = "1")
@Range(min=1) int size, int size,
@Arg(desc = "The maximum height above you to remove from", def = "") @Arg(desc = "The maximum height above you to remove from", def = "")
Integer height) throws WorldEditException { Integer height) throws WorldEditException {
size = Math.max(1, size);
we.checkMaxRadius(size); we.checkMaxRadius(size);
World world = player.getWorld();
height = height != null ? Math.min((world.getMaxY() + 1), height + 1) : (world.getMaxY() + 1);
int affected = editSession.removeAbove(session.getPlacementPosition(player), size, height); int affected = editSession.removeAbove(session.getPlacementPosition(player), size, height);
BBC.VISITOR_BLOCK.send(player, affected); BBC.VISITOR_BLOCK.send(player, affected);
return affected; return affected;
@ -371,9 +382,10 @@ public class UtilityCommands {
@Logging(PLACEMENT) @Logging(PLACEMENT)
public int removeBelow(Player player, LocalSession session, EditSession editSession, public int removeBelow(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The apothem of the square to remove from", def = "1") @Arg(desc = "The apothem of the square to remove from", def = "1")
@Range(min=1) int size, int size,
@Arg(desc = "The maximum height below you to remove from", def = "") @Arg(desc = "The maximum height below you to remove from", def = "")
Integer height) throws WorldEditException { Integer height) throws WorldEditException {
size = Math.max(1, size);
we.checkMaxRadius(size); we.checkMaxRadius(size);
World world = player.getWorld(); World world = player.getWorld();
height = height != null ? Math.min((world.getMaxY() + 1), height + 1) : (world.getMaxY() + 1); height = height != null ? Math.min((world.getMaxY() + 1), height + 1) : (world.getMaxY() + 1);
@ -394,7 +406,8 @@ public class UtilityCommands {
@Arg(desc = "The mask of blocks to remove") @Arg(desc = "The mask of blocks to remove")
Mask mask, Mask mask,
@Arg(desc = "The radius of the square to remove from", def = "50") @Arg(desc = "The radius of the square to remove from", def = "50")
@Range(min=1) int radius) throws WorldEditException { int radius) throws WorldEditException {
radius = Math.max(1, radius);
we.checkMaxRadius(radius); we.checkMaxRadius(radius);
int affected = editSession.removeNear(session.getPlacementPosition(player), mask, radius); int affected = editSession.removeNear(session.getPlacementPosition(player), mask, radius);
@ -411,11 +424,12 @@ public class UtilityCommands {
@Logging(PLACEMENT) @Logging(PLACEMENT)
public int replaceNear(Player player, LocalSession session, EditSession editSession, public int replaceNear(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The radius of the square to remove in") @Arg(desc = "The radius of the square to remove in")
@Range(min=1) int radius, int radius,
@Arg(desc = "The mask matching blocks to remove", def = "") @Arg(desc = "The mask matching blocks to remove", def = "")
Mask from, Mask from,
@Arg(desc = "The pattern of blocks to replace with") @Arg(desc = "The pattern of blocks to replace with")
Pattern to) throws WorldEditException { Pattern to) throws WorldEditException {
radius = Math.max(1, radius);
we.checkMaxRadius(radius); we.checkMaxRadius(radius);
BlockVector3 base = session.getPlacementPosition(player); BlockVector3 base = session.getPlacementPosition(player);
@ -441,7 +455,8 @@ public class UtilityCommands {
@Logging(PLACEMENT) @Logging(PLACEMENT)
public int snow(Player player, LocalSession session, EditSession editSession, public int snow(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The radius of the circle to snow in", def = "10") @Arg(desc = "The radius of the circle to snow in", def = "10")
@Range(min=1) double size) throws WorldEditException { double size) throws WorldEditException {
size = Math.max(1, size);
we.checkMaxRadius(size); we.checkMaxRadius(size);
int affected = editSession.simulateSnow(session.getPlacementPosition(player), size); int affected = editSession.simulateSnow(session.getPlacementPosition(player), size);
@ -458,11 +473,12 @@ public class UtilityCommands {
@Logging(PLACEMENT) @Logging(PLACEMENT)
public int thaw(Player player, LocalSession session, EditSession editSession, public int thaw(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The radius of the circle to thaw in", def = "10") @Arg(desc = "The radius of the circle to thaw in", def = "10")
@Range(min=1) double size) throws WorldEditException { double size) throws WorldEditException {
size = Math.max(1, size);
we.checkMaxRadius(size); we.checkMaxRadius(size);
int affected = editSession.thaw(session.getPlacementPosition(player), size); int affected = editSession.thaw(session.getPlacementPosition(player), size);
player.print(affected + " surfaces thawed."); player.print(affected + " surface(s) thawed.");
return affected; return affected;
} }
@ -475,9 +491,10 @@ public class UtilityCommands {
@Logging(PLACEMENT) @Logging(PLACEMENT)
public int green(Player player, LocalSession session, EditSession editSession, public int green(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The radius of the circle to convert in", def = "10") @Arg(desc = "The radius of the circle to convert in", def = "10")
@Range(min=1) double size, double size,
@Switch(name = 'f', desc = "Also convert coarse dirt") @Switch(name = 'f', desc = "Also convert coarse dirt")
boolean convertCoarse) throws WorldEditException { boolean convertCoarse) throws WorldEditException {
size = Math.max(1, size);
we.checkMaxRadius(size); we.checkMaxRadius(size);
final boolean onlyNormalDirt = !convertCoarse; final boolean onlyNormalDirt = !convertCoarse;
@ -495,12 +512,12 @@ public class UtilityCommands {
@Logging(PLACEMENT) @Logging(PLACEMENT)
public void extinguish(Player player, LocalSession session, EditSession editSession, public void extinguish(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The radius of the square to remove in", def = "") @Arg(desc = "The radius of the square to remove in", def = "")
@Range(min=1) Integer radius) throws WorldEditException { Integer radius) throws WorldEditException {
LocalConfiguration config = we.getConfiguration(); LocalConfiguration config = we.getConfiguration();
int defaultRadius = config.maxRadius != -1 ? Math.min(40, config.maxRadius) : 40; int defaultRadius = config.maxRadius != -1 ? Math.min(40, config.maxRadius) : 40;
int size = radius != null ? radius : defaultRadius; int size = radius != null ? Math.max(1, radius) : defaultRadius;
we.checkMaxRadius(size); we.checkMaxRadius(size);
Mask mask = new BlockTypeMask(editSession, BlockTypes.FIRE); Mask mask = new BlockTypeMask(editSession, BlockTypes.FIRE);
@ -656,7 +673,8 @@ public class UtilityCommands {
return; return;
} }
WorldEditAsyncCommandBuilder.createAndSendMessage(actor, () -> { WorldEditAsyncCommandBuilder.createAndSendMessage(actor, () -> {
double result = expression.evaluateTimeout(WorldEdit.getInstance().getSessionManager().get(actor).getTimeout()); double result = expression.evaluate(
new double[]{}, WorldEdit.getInstance().getSessionManager().get(actor).getTimeout());
String formatted = Double.isNaN(result) ? "NaN" : formatter.format(result); String formatted = Double.isNaN(result) ? "NaN" : formatter.format(result);
return SubtleFormat.wrap(input + " = ").append(TextComponent.of(formatted, TextColor.LIGHT_PURPLE)); return SubtleFormat.wrap(input + " = ").append(TextComponent.of(formatted, TextColor.LIGHT_PURPLE));
}, null); }, null);

View File

@ -374,8 +374,7 @@ public class PrimitiveBindings extends Bindings {
* @param modifiers the list of modifiers to scan * @param modifiers the list of modifiers to scan
* @throws InputParseException on a validation error * @throws InputParseException on a validation error
*/ */
private static void validate(int number, Annotation[] modifiers) private static void validate(int number, Annotation[] modifiers) {
{
for (Annotation modifier : modifiers) { for (Annotation modifier : modifiers) {
if (modifier instanceof Range) { if (modifier instanceof Range) {
Range range = (Range) modifier; Range range = (Range) modifier;

View File

@ -41,7 +41,7 @@ public final class IncendoPaste implements Paster{
* *
* @param pasteApplication The application that is sending the paste * @param pasteApplication The application that is sending the paste
*/ */
public IncendoPaste(final String pasteApplication) { public IncendoPaste(String pasteApplication) {
if (pasteApplication == null || pasteApplication.isEmpty()) { if (pasteApplication == null || pasteApplication.isEmpty()) {
throw new IllegalArgumentException("paste application cannot be null, nor empty"); throw new IllegalArgumentException("paste application cannot be null, nor empty");
} }
@ -57,7 +57,7 @@ public final class IncendoPaste implements Paster{
return new PasteTask(content); return new PasteTask(content);
} }
private final class PasteTask implements Callable<URL>{ private final class PasteTask implements Callable<URL> {
private PasteTask(String content) {} private PasteTask(String content) {}
@ -82,12 +82,12 @@ public final class IncendoPaste implements Paster{
* *
* @param file File to paste * @param file File to paste
*/ */
public void addFile(final PasteFile file) { public void addFile(PasteFile file) {
if (file == null) { if (file == null) {
throw new IllegalArgumentException("File cannot be null"); throw new IllegalArgumentException("File cannot be null");
} }
// Check to see that no duplicate files are submitted // Check to see that no duplicate files are submitted
for (final PasteFile pasteFile : this.files) { for (PasteFile pasteFile : this.files) {
if (pasteFile.fileName.equalsIgnoreCase(file.getFileName())) { if (pasteFile.fileName.equalsIgnoreCase(file.getFileName())) {
throw new IllegalArgumentException(String.format("Found duplicate file with name %s", throw new IllegalArgumentException(String.format("Found duplicate file with name %s",
file.getFileName())); file.getFileName()));
@ -143,7 +143,7 @@ public final class IncendoPaste implements Paster{
httpURLConnection.setRequestProperty("Content-Type", "application/json"); httpURLConnection.setRequestProperty("Content-Type", "application/json");
httpURLConnection.setRequestProperty("Accept", "*/*"); httpURLConnection.setRequestProperty("Accept", "*/*");
httpURLConnection.connect(); httpURLConnection.connect();
try (final OutputStream stream = httpURLConnection.getOutputStream()) { try (OutputStream stream = httpURLConnection.getOutputStream()) {
stream.write(content); stream.write(content);
} }
if (!httpURLConnection.getResponseMessage().contains("OK")) { if (!httpURLConnection.getResponseMessage().contains("OK")) {
@ -151,7 +151,7 @@ public final class IncendoPaste implements Paster{
httpURLConnection.getResponseCode(), httpURLConnection.getResponseMessage())); httpURLConnection.getResponseCode(), httpURLConnection.getResponseMessage()));
} }
final String input; final String input;
try (final BufferedReader inputStream = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()))) { try (BufferedReader inputStream = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()))) {
input = inputStream.lines().map(line -> line + "\n").collect(Collectors.joining()); input = inputStream.lines().map(line -> line + "\n").collect(Collectors.joining());
} }
return input; return input;
@ -171,7 +171,7 @@ public final class IncendoPaste implements Paster{
* @param fileName File name, cannot be empty, nor null * @param fileName File name, cannot be empty, nor null
* @param content File content, cannot be empty, nor null * @param content File content, cannot be empty, nor null
*/ */
public PasteFile(final String fileName, final String content) { public PasteFile(String fileName, String content) {
if (fileName == null || fileName.isEmpty()) { if (fileName == null || fileName.isEmpty()) {
throw new IllegalArgumentException("file name cannot be null, nor empty"); throw new IllegalArgumentException("file name cannot be null, nor empty");
} }
@ -260,10 +260,10 @@ public final class IncendoPaste implements Paster{
} }
} }
private static String readFile(final File file) throws IOException { private static String readFile(File file) throws IOException {
final StringBuilder content = new StringBuilder(); final StringBuilder content = new StringBuilder();
final List<String> lines; final List<String> lines;
try (final BufferedReader reader = new BufferedReader(new FileReader(file))) { try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
lines = reader.lines().collect(Collectors.toList()); lines = reader.lines().collect(Collectors.toList());
} }
for (int i = Math.max(0, lines.size() - 1000); i < lines.size(); i++) { for (int i = Math.max(0, lines.size() - 1000); i < lines.size(); i++) {