2019-06-20 20:05:18 -04:00

375 lines
15 KiB
Java

package com.thevoxelbox.voxelsniper.brush;
import com.thevoxelbox.voxelsniper.Message;
import com.thevoxelbox.voxelsniper.SnipeData;
import com.thevoxelbox.voxelsniper.VoxelSniper;
import org.bukkit.ChatColor;
import org.bukkit.block.BlockState;
import org.bukkit.block.Sign;
import java.io.*;
import java.util.Arrays;
/**
* Overwrites signs.
*
* @author Monofraps
*/
public class SignOverwriteBrush extends Brush {
private static final int MAX_SIGN_LINE_LENGTH = 15;
private static final int NUM_SIGN_LINES = 4;
// these are no array indices
private static final int SIGN_LINE_1 = 1;
private static final int SIGN_LINE_2 = 2;
private static final int SIGN_LINE_3 = 3;
private static final int SIGN_LINE_4 = 4;
private String[] signTextLines = new String[NUM_SIGN_LINES];
private boolean[] signLinesEnabled = new boolean[NUM_SIGN_LINES];
private boolean rangedMode = false;
public SignOverwriteBrush() {
this.setName("Sign Overwrite Brush");
clearBuffer();
resetStates();
}
/**
* Sets the text of a given sign.
*
* @param sign
*/
private void setSignText(final Sign sign) {
for (int i = 0; i < this.signTextLines.length; i++) {
if (this.signLinesEnabled[i]) {
sign.setLine(i, this.signTextLines[i]);
}
}
sign.update();
}
/**
* Sets the text of the target sign if the target block is a sign.
*
* @param v
*/
private void setSingle(final SnipeData v) {
if (this.getTargetBlock().getState() instanceof Sign) {
setSignText((Sign) this.getTargetBlock().getState());
} else {
v.sendMessage(ChatColor.RED + "Target block is not a sign.");
return;
}
}
/**
* Sets all signs in a range of box{x=z=brushSize*2+1 ; z=voxelHeight*2+1}.
*
* @param v
*/
private void setRanged(final SnipeData v) {
final int minX = getTargetBlock().getX() - v.getBrushSize();
final int maxX = getTargetBlock().getX() + v.getBrushSize();
final int minY = getTargetBlock().getY() - v.getVoxelHeight();
final int maxY = getTargetBlock().getY() + v.getVoxelHeight();
final int minZ = getTargetBlock().getZ() - v.getBrushSize();
final int maxZ = getTargetBlock().getZ() + v.getBrushSize();
boolean signFound = false; // indicates whether or not a sign was set
for (int x = minX; x <= maxX; x++) {
for (int y = minY; y <= maxY; y++) {
for (int z = minZ; z <= maxZ; z++) {
BlockState blockState = this.getWorld().getBlockAt(x, y, z).getState();
if (blockState instanceof Sign) {
setSignText((Sign) blockState);
signFound = true;
}
}
}
}
if (!signFound) {
v.sendMessage(ChatColor.RED + "Did not found any sign in selection box.");
}
}
@Override
protected final void arrow(final SnipeData v) {
if (this.rangedMode) {
setRanged(v);
} else {
setSingle(v);
}
}
@Override
protected final void powder(final SnipeData v) {
if (this.getTargetBlock().getState() instanceof Sign) {
Sign sign = (Sign) this.getTargetBlock().getState();
for (int i = 0; i < this.signTextLines.length; i++) {
if (this.signLinesEnabled[i]) {
this.signTextLines[i] = sign.getLine(i);
}
}
displayBuffer(v);
} else {
v.sendMessage(ChatColor.RED + "Target block is not a sign.");
}
}
@Override
public final void parameters(final String[] par, final SnipeData v) {
boolean textChanged = false;
for (int i = 0; i < par.length; i++) {
String parameter = par[i];
try {
if (parameter.equalsIgnoreCase("info")) {
v.sendMessage(ChatColor.AQUA + "Sign Overwrite Brush Powder/Arrow:");
v.sendMessage(ChatColor.BLUE + "The arrow writes the internal line buffer to the target sign.");
v.sendMessage(ChatColor.BLUE + "The powder reads the text of the target sign into the internal buffer.");
v.sendMessage(ChatColor.AQUA + "Sign Overwrite Brush Parameters:");
v.sendMessage(ChatColor.GREEN + "-1[:(enabled|disabled)] ... " + ChatColor.BLUE + "-- Sets the text of the first sign line. (e.g. -1 Blah Blah)");
v.sendMessage(ChatColor.GREEN + "-2[:(enabled|disabled)] ... " + ChatColor.BLUE + "-- Sets the text of the second sign line. (e.g. -2 Blah Blah)");
v.sendMessage(ChatColor.GREEN + "-3[:(enabled|disabled)] ... " + ChatColor.BLUE + "-- Sets the text of the third sign line. (e.g. -3 Blah Blah)");
v.sendMessage(ChatColor.GREEN + "-4[:(enabled|disabled)] ... " + ChatColor.BLUE + "-- Sets the text of the fourth sign line. (e.g. -4 Blah Blah)");
v.sendMessage(ChatColor.GREEN + "-clear " + ChatColor.BLUE + "-- Clears the line buffer. (Alias: -c)");
v.sendMessage(ChatColor.GREEN + "-clearall " + ChatColor.BLUE + "-- Clears the line buffer and sets all lines back to enabled. (Alias: -ca)");
v.sendMessage(ChatColor.GREEN + "-multiple [on|off] " + ChatColor.BLUE + "-- Enables or disables ranged mode. (Alias: -m) (see Wiki for more information)");
v.sendMessage(ChatColor.GREEN + "-save (name) " + ChatColor.BLUE + "-- Save you buffer to a file named [name]. (Alias: -s)");
v.sendMessage(ChatColor.GREEN + "-open (name) " + ChatColor.BLUE + "-- Loads a buffer from a file named [name]. (Alias: -o)");
} else if (parameter.startsWith("-1")) {
textChanged = true;
i = parseSignLineFromParam(par, SIGN_LINE_1, v, i);
} else if (parameter.startsWith("-2")) {
textChanged = true;
i = parseSignLineFromParam(par, SIGN_LINE_2, v, i);
} else if (parameter.startsWith("-3")) {
textChanged = true;
i = parseSignLineFromParam(par, SIGN_LINE_3, v, i);
} else if (parameter.startsWith("-4")) {
textChanged = true;
i = parseSignLineFromParam(par, SIGN_LINE_4, v, i);
} else if (parameter.equalsIgnoreCase("-clear") || parameter.equalsIgnoreCase("-c")) {
clearBuffer();
v.sendMessage(ChatColor.BLUE + "Internal text buffer cleard.");
} else if (parameter.equalsIgnoreCase("-clearall") || parameter.equalsIgnoreCase("-ca")) {
clearBuffer();
resetStates();
v.sendMessage(ChatColor.BLUE + "Internal text buffer cleard and states back to enabled.");
} else if (parameter.equalsIgnoreCase("-multiple") || parameter.equalsIgnoreCase("-m")) {
if ((i + 1) >= par.length) {
v.sendMessage(ChatColor.RED + String.format("Missing parameter after %s.", parameter));
continue;
}
rangedMode = (par[++i].equalsIgnoreCase("on") || par[++i].equalsIgnoreCase("yes"));
v.sendMessage(ChatColor.BLUE + String.format("Ranged mode is %s", ChatColor.GREEN + (rangedMode ? "enabled" : "disabled")));
if (this.rangedMode) {
v.sendMessage(ChatColor.GREEN + "Brush size set to " + ChatColor.RED + v.getBrushSize());
v.sendMessage(ChatColor.AQUA + "Brush height set to " + ChatColor.RED + v.getVoxelHeight());
}
} else if (parameter.equalsIgnoreCase("-save") || parameter.equalsIgnoreCase("-s")) {
if ((i + 1) >= par.length) {
v.sendMessage(ChatColor.RED + String.format("Missing parameter after %s.", parameter));
continue;
}
String fileName = par[++i];
saveBufferToFile(fileName, v);
} else if (parameter.equalsIgnoreCase("-open") || parameter.equalsIgnoreCase("-o")) {
if ((i + 1) >= par.length) {
v.sendMessage(ChatColor.RED + String.format("Missing parameter after %s.", parameter));
continue;
}
String fileName = par[++i];
loadBufferFromFile(fileName, "", v);
textChanged = true;
}
} catch (Exception exception) {
v.sendMessage(ChatColor.RED + String.format("Error while parsing parameter %s", parameter));
exception.printStackTrace();
}
}
if (textChanged) {
displayBuffer(v);
}
}
/**
* Parses parameter input text of line [param:lineNumber].
* Iterates though the given array until the next top level param (a parameter which starts
* with a dash -) is found.
*
* @param params
* @param lineNumber
* @param v
* @param i
* @return
*/
private int parseSignLineFromParam(final String[] params, final int lineNumber, final SnipeData v, int i) {
final int lineIndex = lineNumber - 1;
final String parameter = params[i];
boolean statusSet = false;
if (parameter.contains(":")) {
this.signLinesEnabled[lineIndex] = parameter.substring(parameter.indexOf(":")).equalsIgnoreCase(":enabled");
v.sendMessage(ChatColor.BLUE + "Line " + lineNumber + " is " + ChatColor.GREEN + (this.signLinesEnabled[lineIndex] ? "enabled" : "disabled"));
statusSet = true;
}
if ((i + 1) >= params.length) {
// return if the user just wanted to set the status
if (statusSet) {
return i;
}
v.sendMessage(ChatColor.RED + "Warning: No text after -" + lineNumber + ". Setting buffer text to \"\" (empty string)");
signTextLines[lineIndex] = "";
return i;
}
StringBuilder newText = new StringBuilder();
// go through the array until the next top level parameter is found
for (i++; i < params.length; i++) {
final String currentParameter = params[i];
if (currentParameter.startsWith("-")) {
i--;
break;
} else {
newText.append(currentParameter).append(" ");
}
}
newText = new StringBuilder(ChatColor.translateAlternateColorCodes('&', newText.toString()));
// remove last space or return if the string is empty and the user just wanted to set the status
if ((newText.length() > 0) && newText.toString().endsWith(" ")) {
newText = new StringBuilder(newText.substring(0, newText.length() - 1));
} else if (newText.length() == 0) {
if (statusSet) {
return i;
}
v.sendMessage(ChatColor.RED + "Warning: No text after -" + lineNumber + ". Setting buffer text to \"\" (empty string)");
}
// check the line length and cut the text if needed
if (newText.length() > MAX_SIGN_LINE_LENGTH) {
v.sendMessage(ChatColor.RED + "Warning: Text on line " + lineNumber + " exceeds the maximum line length of " + MAX_SIGN_LINE_LENGTH + " characters. Your text will be cut.");
newText = new StringBuilder(newText.substring(0, MAX_SIGN_LINE_LENGTH));
}
this.signTextLines[lineIndex] = newText.toString();
return i;
}
private void displayBuffer(final SnipeData v) {
v.sendMessage(ChatColor.BLUE + "Buffer text set to: ");
for (int i = 0; i < this.signTextLines.length; i++) {
v.sendMessage((this.signLinesEnabled[i] ? ChatColor.GREEN + "(E): " : ChatColor.RED + "(D): ") + ChatColor.BLACK + this.signTextLines[i]);
}
}
/**
* Saves the buffer to file.
*
* @param fileName
* @param v
*/
private void saveBufferToFile(final String fileName, final SnipeData v) {
final File store = new File(VoxelSniper.getInstance().getDataFolder() + "/" + fileName + ".vsign");
if (store.exists()) {
v.sendMessage("This file already exists.");
return;
}
try {
store.createNewFile();
try (FileWriter outFile = new FileWriter(store); BufferedWriter outStream = new BufferedWriter(outFile)) {
for (int i = 0; i < this.signTextLines.length; i++) {
outStream.write(this.signLinesEnabled[i] + "\n");
outStream.write(this.signTextLines[i] + "\n");
}
}
v.sendMessage(ChatColor.BLUE + "File saved successfully.");
} catch (IOException exception) {
v.sendMessage(ChatColor.RED + "Failed to save file. " + exception.getMessage());
exception.printStackTrace();
}
}
/**
* Loads a buffer from a file.
*
* @param fileName
* @param userDomain
* @param v
*/
private void loadBufferFromFile(final String fileName, final String userDomain, final SnipeData v) {
final File store = new File(VoxelSniper.getInstance().getDataFolder() + "/" + fileName + ".vsign");
if (!store.exists()) {
v.sendMessage("This file does not exist.");
return;
}
try (FileReader inFile = new FileReader(store); BufferedReader inStream = new BufferedReader(inFile)) {
for (int i = 0; i < this.signTextLines.length; i++) {
this.signLinesEnabled[i] = Boolean.parseBoolean(inStream.readLine());
this.signTextLines[i] = inStream.readLine();
}
v.sendMessage(ChatColor.BLUE + "File loaded successfully.");
} catch (IOException exception) {
v.sendMessage(ChatColor.RED + "Failed to load file. " + exception.getMessage());
exception.printStackTrace();
}
}
/**
* Clears the internal text buffer. (Sets it to empty strings)
*/
private void clearBuffer() {
Arrays.fill(this.signTextLines, "");
}
/**
* Resets line enabled states to enabled.
*/
private void resetStates() {
Arrays.fill(this.signLinesEnabled, true);
}
@Override
public final void info(final Message vm) {
vm.brushName("Sign Overwrite Brush");
vm.custom(ChatColor.BLUE + "Buffer text: ");
for (int i = 0; i < this.signTextLines.length; i++) {
vm.custom((this.signLinesEnabled[i] ? ChatColor.GREEN + "(E): " : ChatColor.RED + "(D): ") + ChatColor.BLACK + this.signTextLines[i]);
}
vm.custom(ChatColor.BLUE + String.format("Ranged mode is %s", ChatColor.GREEN + (rangedMode ? "enabled" : "disabled")));
if (rangedMode) {
vm.size();
vm.height();
}
}
@Override
public String getPermissionNode() {
return "voxelsniper.brush.signoverwrite";
}
}