mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2025-06-11 20:13:55 +00:00
It started on work with commands then I got carried away.
This commit is contained in:
@ -5,7 +5,6 @@ import com.boydti.fawe.IFawe;
|
||||
import com.boydti.fawe.beta.implementation.QueueHandler;
|
||||
import com.boydti.fawe.bukkit.beta.BukkitQueue;
|
||||
import com.boydti.fawe.bukkit.beta.BukkitQueueHandler;
|
||||
import com.boydti.fawe.bukkit.chat.BukkitChatManager;
|
||||
import com.boydti.fawe.bukkit.listener.BrushListener;
|
||||
import com.boydti.fawe.bukkit.listener.BukkitImageListener;
|
||||
import com.boydti.fawe.bukkit.listener.CFIPacketListener;
|
||||
@ -97,11 +96,6 @@ public class FaweBukkit implements IFawe, Listener {
|
||||
if (Bukkit.getVersion().contains("git-Paper") && Settings.IMP.EXPERIMENTAL.DYNAMIC_CHUNK_RENDERING > 1) {
|
||||
new RenderListener(plugin);
|
||||
}
|
||||
try {
|
||||
Fawe.get().setChatManager(new BukkitChatManager());
|
||||
} catch (Throwable throwable) {
|
||||
throwable.printStackTrace();
|
||||
}
|
||||
} catch (final Throwable e) {
|
||||
e.printStackTrace();
|
||||
Bukkit.getServer().shutdown();
|
||||
|
@ -1,64 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.chat;
|
||||
|
||||
import com.boydti.fawe.bukkit.BukkitPlayer;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.util.chat.ChatManager;
|
||||
import com.boydti.fawe.util.chat.Message;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.bukkit.ChatColor;
|
||||
|
||||
public class BukkitChatManager implements ChatManager<FancyMessage> {
|
||||
|
||||
@Override
|
||||
public FancyMessage builder() {
|
||||
return new FancyMessage("");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void color(Message message, String color) {
|
||||
message.$(this).color(ChatColor.getByChar(BBC.color(color).substring(1)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tooltip(Message message, Message... tooltips) {
|
||||
List<FancyMessage> lines = new ArrayList<>();
|
||||
for (Message tooltip : tooltips) {
|
||||
lines.add(tooltip.$(this));
|
||||
}
|
||||
message.$(this).formattedTooltip(lines);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void command(Message message, String command) {
|
||||
message.$(this).command(command);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void text(Message message, String text) {
|
||||
message.$(this).color(BBC.color(text));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Message Message, FawePlayer player) {
|
||||
if (!(player instanceof BukkitPlayer)) {
|
||||
player.sendMessage(Message.$(this).toOldMessageFormat());
|
||||
} else {
|
||||
Message.$(this).send(((BukkitPlayer) player).parent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suggest(Message Message, String command) {
|
||||
Message.$(this).suggest(command);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void link(Message Message, String url) {
|
||||
Message.$(this).link(url);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,874 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.chat;
|
||||
|
||||
import static com.boydti.fawe.bukkit.chat.TextualComponent.rawText;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
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.logging.Level;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerialization;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* 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>. This
|
||||
* class allows plugins to emulate the functionality of the vanilla Minecraft <a
|
||||
* href="http://minecraft.gamepedia.com/Commands#tellraw">tellraw command</a>.
|
||||
* <p>
|
||||
* This class follows the builder pattern, allowing for method chaining. It is set up such that
|
||||
* invocations of property-setting methods will affect the current editing component, and a call to
|
||||
* {@link #then()} or {@link #then(String)} will append a new editing component to the end of the
|
||||
* message, optionally initializing it with text. Further property-setting method calls will affect
|
||||
* that editing component.
|
||||
* </p>
|
||||
*/
|
||||
public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<MessagePart>,
|
||||
ConfigurationSerializable {
|
||||
|
||||
static {
|
||||
ConfigurationSerialization.registerClass(FancyMessage.class);
|
||||
}
|
||||
|
||||
private List<MessagePart> messageParts;
|
||||
private int index;
|
||||
private String jsonString;
|
||||
private boolean dirty;
|
||||
|
||||
private static Constructor<?> nmsPacketPlayOutChatConstructor;
|
||||
|
||||
@Override
|
||||
public FancyMessage clone() throws CloneNotSupportedException {
|
||||
FancyMessage instance = (FancyMessage) super.clone();
|
||||
instance.messageParts = new ArrayList<>(messageParts.size());
|
||||
for (int i = 0; i < messageParts.size(); i++) {
|
||||
instance.messageParts.add(i, messageParts.get(i).clone());
|
||||
}
|
||||
instance.index = index;
|
||||
instance.dirty = false;
|
||||
instance.jsonString = null;
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JSON message with text.
|
||||
*
|
||||
* @param firstPartText The existing text in the message.
|
||||
*/
|
||||
public FancyMessage(String firstPartText) {
|
||||
this(rawText(firstPartText));
|
||||
}
|
||||
|
||||
private FancyMessage(TextualComponent firstPartText) {
|
||||
messageParts = new ArrayList<>();
|
||||
messageParts.add(new MessagePart(firstPartText));
|
||||
index = messageParts.size();
|
||||
jsonString = null;
|
||||
dirty = false;
|
||||
if (nmsPacketPlayOutChatConstructor == null) {
|
||||
try {
|
||||
nmsPacketPlayOutChatConstructor = Reflection.getNMSClass("PacketPlayOutChat")
|
||||
.getDeclaredConstructor(Reflection.getNMSClass("IChatBaseComponent"));
|
||||
nmsPacketPlayOutChatConstructor.setAccessible(true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
Bukkit.getLogger()
|
||||
.log(Level.SEVERE, "Could not find Minecraft method or constructor.", e);
|
||||
} catch (SecurityException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Could not access constructor.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JSON message without text.
|
||||
*/
|
||||
public FancyMessage() {
|
||||
this((TextualComponent) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the text of the current editing component to a value.
|
||||
*
|
||||
* @param text The new text of the current editing component.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage text(String text) {
|
||||
MessagePart latest = latest();
|
||||
latest.text = rawText(text);
|
||||
dirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the text of the current editing component to a value.
|
||||
*
|
||||
* @param text The new text of the current editing component.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage text(TextualComponent text) {
|
||||
MessagePart latest = latest();
|
||||
latest.text = text;
|
||||
dirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param text Text with coloring
|
||||
* @return This builder instance.
|
||||
* @throws IllegalArgumentException If the specified {@code ChatColor} enumeration value is not
|
||||
* a color (but a format value).
|
||||
*/
|
||||
public FancyMessage color(String text) {
|
||||
index = messageParts.size();
|
||||
boolean color = false;
|
||||
ArrayDeque<ChatColor> colors = new ArrayDeque<>();
|
||||
int last = 0;
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
char c = text.charAt(i);
|
||||
if (color != (color = false)) {
|
||||
ChatColor chatColor = ChatColor.getByChar(c);
|
||||
if (chatColor != null) {
|
||||
if (i - last > 1) {
|
||||
append(text.substring(last, i - 1));
|
||||
colors.forEach(this::color);
|
||||
colors.clear();
|
||||
}
|
||||
colors.add(chatColor);
|
||||
last = i + 1;
|
||||
}
|
||||
}
|
||||
if (c == '\u00A7') {
|
||||
color = true;
|
||||
}
|
||||
}
|
||||
if (text.length() - last > 0) {
|
||||
append(text.substring(last));
|
||||
colors.forEach(this::color);
|
||||
}
|
||||
index++;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color of the current editing component to a value.<br /> Setting the color will
|
||||
* clear current styles
|
||||
*
|
||||
* @param color The new color of the current editing component.
|
||||
* @return This builder instance.
|
||||
* @throws IllegalArgumentException If the specified {@code ChatColor} enumeration value is not
|
||||
* a color (but a format value).
|
||||
*/
|
||||
public FancyMessage color(ChatColor color) {
|
||||
if (!color.isColor()) {
|
||||
if (color.isFormat()) {
|
||||
return style(color);
|
||||
}
|
||||
if (color == ChatColor.RESET) {
|
||||
color = ChatColor.WHITE;
|
||||
}
|
||||
} else {
|
||||
latest().styles.clear();
|
||||
}
|
||||
latest().color = color;
|
||||
dirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the stylization of the current editing component.
|
||||
*
|
||||
* @param styles The array of styles to apply to the editing component.
|
||||
* @return This builder instance.
|
||||
* @throws IllegalArgumentException If any of the enumeration values in the array do not
|
||||
* represent formatters.
|
||||
*/
|
||||
public FancyMessage style(ChatColor... styles) {
|
||||
for (ChatColor style : styles) {
|
||||
if (!style.isFormat()) {
|
||||
color(style);
|
||||
}
|
||||
}
|
||||
latest().styles.addAll(Arrays.asList(styles));
|
||||
dirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage file(String path) {
|
||||
onClick("open_file", path);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage link(String url) {
|
||||
onClick("open_url", url);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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. 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.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage suggest(String command) {
|
||||
onClick("suggest_command", command);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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. 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.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage insert(String command) {
|
||||
onCurrent(m -> m.insertionData = command);
|
||||
dirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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. 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.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage command(String command) {
|
||||
onClick("run_command", command);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the behavior of the current editing component to display raw 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 text The text, which supports newlines, which will be displayed to the client upon
|
||||
* hovering.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage tooltip(String text) {
|
||||
onHover("show_text", new JsonString(text));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the behavior of the current editing component to display raw 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.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage tooltip(Iterable<String> lines) {
|
||||
tooltip(ArrayWrapper.toArray(lines, String.class));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the behavior of the current editing component to display raw 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.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage tooltip(String... lines) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
builder.append(lines[i]);
|
||||
if (i != lines.length - 1) {
|
||||
builder.append('\n');
|
||||
}
|
||||
}
|
||||
tooltip(builder.toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the behavior of the current editing component to display formatted 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 text The formatted text which will be displayed to the client upon hovering.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage formattedTooltip(FancyMessage text) {
|
||||
for (MessagePart component : text.messageParts) {
|
||||
if (component.clickActionData != null && component.clickActionName != null) {
|
||||
throw new IllegalArgumentException("The tooltip text cannot have click data.");
|
||||
} else if (component.hoverActionData != null && component.hoverActionName != null) {
|
||||
throw new IllegalArgumentException("The tooltip text cannot have a tooltip.");
|
||||
}
|
||||
}
|
||||
onHover("show_text", text);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the behavior of the current editing component to display the specified lines of formatted
|
||||
* 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.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage formattedTooltip(FancyMessage... lines) {
|
||||
if (lines.length < 1) {
|
||||
onHover(null, null); // Clear tooltip
|
||||
return this;
|
||||
}
|
||||
|
||||
FancyMessage result = new FancyMessage();
|
||||
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++) {
|
||||
try {
|
||||
for (MessagePart component : lines[i]) {
|
||||
if (component.clickActionData != null && component.clickActionName != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"The tooltip text cannot have click data.");
|
||||
} else if (component.hoverActionData != null
|
||||
&& component.hoverActionName != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"The tooltip text cannot have a tooltip.");
|
||||
}
|
||||
if (component.hasText()) {
|
||||
result.messageParts.add(component.clone());
|
||||
result.index = result.messageParts.size();
|
||||
}
|
||||
}
|
||||
if (i != lines.length - 1) {
|
||||
result.messageParts.add(new MessagePart(rawText("\n")));
|
||||
result.index = result.messageParts.size();
|
||||
}
|
||||
} catch (CloneNotSupportedException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Failed to clone object", e);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
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.
|
||||
* <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.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage formattedTooltip(Iterable<FancyMessage> lines) {
|
||||
return formattedTooltip(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.
|
||||
*
|
||||
* @param replacements The replacements, in order, that will be used in the language-specific
|
||||
* message.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage translationReplacements(String... replacements) {
|
||||
for (String str : replacements) {
|
||||
latest().translationReplacements.add(new JsonString(str));
|
||||
}
|
||||
dirty = true;
|
||||
|
||||
return this;
|
||||
}
|
||||
/*
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @return This builder instance.
|
||||
*/ /* ------------
|
||||
public FancyMessage translationReplacements(final Iterable<? extends CharSequence> replacements){
|
||||
for(CharSequence str : replacements){
|
||||
latest().translationReplacements.add(new JsonString(str));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage translationReplacements(FancyMessage... replacements) {
|
||||
Collections.addAll(latest().translationReplacements, replacements);
|
||||
|
||||
dirty = true;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage translationReplacements(Iterable<FancyMessage> replacements) {
|
||||
return translationReplacements(
|
||||
ArrayWrapper.toArray(replacements, FancyMessage.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminate construction of the current editing component, and begin construction of a new
|
||||
* 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.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage then(String text) {
|
||||
return then(rawText(text));
|
||||
}
|
||||
|
||||
private FancyMessage append(String text) {
|
||||
if (!latest().hasText()) {
|
||||
throw new IllegalStateException("previous message part has no text");
|
||||
}
|
||||
MessagePart latest = latest();
|
||||
messageParts.add(new MessagePart(rawText(text)));
|
||||
latest().color = latest.color;
|
||||
latest().styles.addAll(latest.styles);
|
||||
dirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminate construction of the current editing component, and begin construction of a new
|
||||
* 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.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage then(TextualComponent text) {
|
||||
if (!latest().hasText()) {
|
||||
throw new IllegalStateException("previous message part has no text");
|
||||
}
|
||||
messageParts.add(new MessagePart(text));
|
||||
index = messageParts.size();
|
||||
dirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminate construction of the current editing component, and begin construction of a new
|
||||
* 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.
|
||||
*/
|
||||
public FancyMessage then() {
|
||||
if (!latest().hasText()) {
|
||||
throw new IllegalStateException("previous message part has no text");
|
||||
}
|
||||
messageParts.add(new MessagePart());
|
||||
index = messageParts.size();
|
||||
dirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeJson(JsonWriter writer) throws IOException {
|
||||
if (messageParts.size() == 1) {
|
||||
latest().writeJson(writer);
|
||||
} else {
|
||||
writer.beginObject().name("text").value("").name("extra").beginArray();
|
||||
for (MessagePart part : this) {
|
||||
part.writeJson(writer);
|
||||
}
|
||||
writer.endArray().endObject();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize this fancy message, converting it into syntactically-valid JSON using a {@link
|
||||
* JsonWriter}. This JSON should be compatible with vanilla formatter commands such as {@code
|
||||
* /tellraw}.
|
||||
*
|
||||
* @return The JSON string representing this object.
|
||||
*/
|
||||
public String toJSONString() {
|
||||
if (!dirty && jsonString != null) {
|
||||
return jsonString;
|
||||
}
|
||||
StringWriter string = new StringWriter();
|
||||
JsonWriter json = new JsonWriter(string);
|
||||
try {
|
||||
writeJson(json);
|
||||
json.close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("invalid message");
|
||||
}
|
||||
jsonString = string.toString();
|
||||
dirty = false;
|
||||
return jsonString;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public void send(Player player) {
|
||||
send(player, toJSONString());
|
||||
}
|
||||
|
||||
private void send(CommandSender sender, String jsonString) {
|
||||
if (!(sender instanceof Player)) {
|
||||
sender.sendMessage(toOldMessageFormat());
|
||||
return;
|
||||
}
|
||||
Player player = (Player) sender;
|
||||
try {
|
||||
Object handle = Reflection.getHandle(player);
|
||||
Object connection = Reflection.getField(handle.getClass(), "playerConnection")
|
||||
.get(handle);
|
||||
Reflection
|
||||
.getMethod(connection.getClass(), "sendPacket", Reflection.getNMSClass("Packet"))
|
||||
.invoke(connection, createChatPacket(jsonString));
|
||||
} catch (IllegalArgumentException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e);
|
||||
} catch (InstantiationException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Underlying class is abstract.", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
Bukkit.getLogger()
|
||||
.log(Level.WARNING, "A error has occurred during invoking of method.", e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Could not find method.", e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Could not find class.", e);
|
||||
}
|
||||
}
|
||||
|
||||
// The ChatSerializer's instance of Gson
|
||||
private static Object nmsChatSerializerGsonInstance;
|
||||
private static Method fromJsonMethod;
|
||||
|
||||
private Object createChatPacket(String json)
|
||||
throws IllegalArgumentException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException {
|
||||
if (nmsChatSerializerGsonInstance == null) {
|
||||
// Find the field and its value, completely bypassing obfuscation
|
||||
Class<?> chatSerializerClazz;
|
||||
|
||||
// Get the three parts of the version string (major version is currently unused)
|
||||
// vX_Y_RZ
|
||||
// X = major
|
||||
// Y = minor
|
||||
// Z = revision
|
||||
final String version = Reflection.getVersion();
|
||||
String[] split = version.substring(1, version.length() - 1)
|
||||
.split("_"); // Remove trailing dot
|
||||
//int majorVersion = Integer.parseInt(split[0]);
|
||||
int minorVersion = Integer.parseInt(split[1]);
|
||||
int revisionVersion = Integer.parseInt(split[2].substring(1)); // Substring to ignore R
|
||||
|
||||
if (minorVersion < 8 || minorVersion == 8 && revisionVersion == 1) {
|
||||
chatSerializerClazz = Reflection.getNMSClass("ChatSerializer");
|
||||
} else {
|
||||
chatSerializerClazz = Reflection.getNMSClass("IChatBaseComponent$ChatSerializer");
|
||||
}
|
||||
|
||||
if (chatSerializerClazz == null) {
|
||||
throw new ClassNotFoundException("Can't find the ChatSerializer class");
|
||||
}
|
||||
|
||||
for (Field declaredField : chatSerializerClazz.getDeclaredFields()) {
|
||||
if (Modifier.isFinal(declaredField.getModifiers()) && Modifier
|
||||
.isStatic(declaredField.getModifiers()) && declaredField.getType().getName()
|
||||
.endsWith("Gson")) {
|
||||
// We've found our field
|
||||
declaredField.setAccessible(true);
|
||||
nmsChatSerializerGsonInstance = declaredField.get(null);
|
||||
fromJsonMethod = nmsChatSerializerGsonInstance.getClass()
|
||||
.getMethod("fromJson", String.class, Class.class);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
Object serializedChatComponent = fromJsonMethod.invoke(nmsChatSerializerGsonInstance, json,
|
||||
Reflection.getNMSClass("IChatBaseComponent"));
|
||||
|
||||
return nmsPacketPlayOutChatConstructor.newInstance(serializedChatComponent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends this message to a command sender. If the sender is a player, they will receive the
|
||||
* fully-fledged formatted display of this message. Otherwise, they will receive a version of
|
||||
* this message with less formatting.
|
||||
*
|
||||
* @param sender The command sender who will receive the message.
|
||||
* @see #toOldMessageFormat()
|
||||
*/
|
||||
public void send(CommandSender sender) {
|
||||
send(sender, toJSONString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends this message to multiple command senders.
|
||||
*
|
||||
* @param senders The command senders who will receive the message.
|
||||
* @see #send(CommandSender)
|
||||
*/
|
||||
public void send(Iterable<? extends CommandSender> senders) {
|
||||
String string = toJSONString();
|
||||
for (CommandSender sender : senders) {
|
||||
send(sender, string);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert this message to a human-readable string with limited formatting. This method is used
|
||||
* to send this message to clients without JSON formatting support.
|
||||
* <p>
|
||||
* Serialization of this message by using this message will include (in this order for each
|
||||
* message part):
|
||||
* <ol>
|
||||
* <li>The color of each message part.</li>
|
||||
* <li>The applicable stylizations for each message part.</li>
|
||||
* <li>The core text of the message part.</li>
|
||||
* </ol>
|
||||
* The primary omissions are tooltips and clickable actions. Consequently, this method should be used only as a last resort.
|
||||
* </p>
|
||||
* <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.
|
||||
*/
|
||||
public String toOldMessageFormat() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (MessagePart part : this) {
|
||||
result.append(part.color == null ? "" : part.color);
|
||||
for (ChatColor formatSpecifier : part.styles) {
|
||||
result.append(formatSpecifier);
|
||||
}
|
||||
result.append(part.text);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private void onCurrent(Consumer<MessagePart> call) {
|
||||
for (int i = index - 1; i < messageParts.size(); i++) {
|
||||
call.accept(messageParts.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
private MessagePart latest() {
|
||||
return messageParts.get(messageParts.size() - 1);
|
||||
}
|
||||
|
||||
private void onClick(String name, String data) {
|
||||
onCurrent(m -> {
|
||||
m.clickActionName = name;
|
||||
m.clickActionData = data;
|
||||
});
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
private void onHover(String name, JsonRepresentedObject data) {
|
||||
onCurrent(m -> {
|
||||
m.hoverActionName = name;
|
||||
m.hoverActionData = data;
|
||||
});
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
// Doc copied from interface
|
||||
@Override
|
||||
public Map<String, Object> serialize() {
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("messageParts", messageParts);
|
||||
// map.put("JSON", toJSONString());
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes a JSON-represented message from a mapping of key-value pairs. This is called by
|
||||
* the Bukkit serialization API. It is not intended for direct public API consumption.
|
||||
*
|
||||
* @param serialized The key-value mapping which represents a fancy message.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static FancyMessage deserialize(Map<String, Object> serialized) {
|
||||
FancyMessage msg = new FancyMessage();
|
||||
msg.messageParts = (List<MessagePart>) serialized.get("messageParts");
|
||||
msg.jsonString = serialized.containsKey("JSON") ? serialized.get("JSON").toString() : null;
|
||||
msg.dirty = !serialized.containsKey("JSON");
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>Internally called method. Not for API consumption.</b>
|
||||
*/
|
||||
@Override
|
||||
@NotNull
|
||||
public Iterator<MessagePart> iterator() {
|
||||
return messageParts.iterator();
|
||||
}
|
||||
|
||||
private static JsonParser _stringParser = new JsonParser();
|
||||
|
||||
/**
|
||||
* Deserializes a fancy message from its JSON representation. This JSON representation is of the
|
||||
* format of that returned by {@link #toJSONString()}, and is compatible with vanilla inputs.
|
||||
*
|
||||
* @param json The JSON string which represents a fancy message.
|
||||
* @return A {@code FancyMessage} representing the parameterized JSON message.
|
||||
*/
|
||||
public static FancyMessage deserialize(String json) {
|
||||
JsonObject serialized = _stringParser.parse(json).getAsJsonObject();
|
||||
JsonArray extra = serialized.getAsJsonArray("extra"); // Get the extra component
|
||||
FancyMessage returnVal = new FancyMessage();
|
||||
returnVal.messageParts.clear();
|
||||
for (JsonElement mPrt : extra) {
|
||||
MessagePart component = new MessagePart();
|
||||
JsonObject messagePart = mPrt.getAsJsonObject();
|
||||
for (Map.Entry<String, JsonElement> entry : messagePart.entrySet()) {
|
||||
// Deserialize text
|
||||
if (TextualComponent.isTextKey(entry.getKey())) {
|
||||
// The map mimics the YAML serialization, which has a "key" field and one or more "value" fields
|
||||
Map<String, Object> serializedMapForm = new HashMap<>(); // Must be object due to Bukkit serializer API compliance
|
||||
serializedMapForm.put("key", entry.getKey());
|
||||
if (entry.getValue().isJsonPrimitive()) {
|
||||
// Assume string
|
||||
serializedMapForm.put("value", entry.getValue().getAsString());
|
||||
} else {
|
||||
// Composite object, but we assume each element is a string
|
||||
for (Map.Entry<String, JsonElement> compositeNestedElement : entry
|
||||
.getValue().getAsJsonObject().entrySet()) {
|
||||
serializedMapForm.put("value." + compositeNestedElement.getKey(),
|
||||
compositeNestedElement.getValue().getAsString());
|
||||
}
|
||||
}
|
||||
component.text = TextualComponent.deserialize(serializedMapForm);
|
||||
} else if (MessagePart.stylesToNames.inverse().containsKey(entry.getKey())) {
|
||||
if (entry.getValue().getAsBoolean()) {
|
||||
component.styles
|
||||
.add(MessagePart.stylesToNames.inverse().get(entry.getKey()));
|
||||
}
|
||||
} else if (entry.getKey().equals("color")) {
|
||||
component.color = ChatColor.valueOf(entry.getValue().getAsString().toUpperCase());
|
||||
} else if (entry.getKey().equals("clickEvent")) {
|
||||
JsonObject object = entry.getValue().getAsJsonObject();
|
||||
component.clickActionName = object.get("action").getAsString();
|
||||
component.clickActionData = object.get("value").getAsString();
|
||||
} else if (entry.getKey().equals("hoverEvent")) {
|
||||
JsonObject object = entry.getValue().getAsJsonObject();
|
||||
component.hoverActionName = object.get("action").getAsString();
|
||||
if (object.get("value").isJsonPrimitive()) {
|
||||
// Assume string
|
||||
component.hoverActionData = new JsonString(
|
||||
object.get("value").getAsString());
|
||||
} else {
|
||||
// Assume composite type
|
||||
// The only composite type we currently store is another FancyMessage
|
||||
// Therefore, recursion time!
|
||||
component.hoverActionData = deserialize(object.get("value")
|
||||
.toString() /* This should properly serialize the JSON object as a JSON string */);
|
||||
}
|
||||
} else if (entry.getKey().equals("insertion")) {
|
||||
component.insertionData = entry.getValue().getAsString();
|
||||
} else if (entry.getKey().equals("with")) {
|
||||
for (JsonElement object : entry.getValue().getAsJsonArray()) {
|
||||
if (object.isJsonPrimitive()) {
|
||||
component.translationReplacements
|
||||
.add(new JsonString(object.getAsString()));
|
||||
} else {
|
||||
// Only composite type stored in this array is - again - FancyMessages
|
||||
// Recurse within this function to parse this as a translation replacement
|
||||
component.translationReplacements.add(deserialize(object.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
returnVal.messageParts.add(component);
|
||||
returnVal.index = returnVal.messageParts.size();
|
||||
}
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
}
|
@ -1,156 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.chat;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerialization;
|
||||
|
||||
/**
|
||||
* Internal class: Represents a component of a JSON-serializable {@link FancyMessage}.
|
||||
*/
|
||||
final class MessagePart implements JsonRepresentedObject, ConfigurationSerializable, Cloneable {
|
||||
|
||||
ChatColor color = ChatColor.WHITE;
|
||||
ArrayList<ChatColor> styles = new ArrayList<>();
|
||||
String clickActionName = null;
|
||||
String clickActionData = null;
|
||||
String hoverActionName = null;
|
||||
JsonRepresentedObject hoverActionData = null;
|
||||
TextualComponent text = null;
|
||||
String insertionData = null;
|
||||
ArrayList<JsonRepresentedObject> translationReplacements = new ArrayList<>();
|
||||
|
||||
MessagePart(final TextualComponent text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
MessagePart() {
|
||||
this.text = null;
|
||||
}
|
||||
|
||||
boolean hasText() {
|
||||
return text != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public MessagePart clone() throws CloneNotSupportedException {
|
||||
MessagePart obj = (MessagePart) super.clone();
|
||||
obj.styles = (ArrayList<ChatColor>) styles.clone();
|
||||
if (hoverActionData instanceof JsonString) {
|
||||
obj.hoverActionData = new JsonString(((JsonString) hoverActionData).getValue());
|
||||
} else if (hoverActionData instanceof FancyMessage) {
|
||||
obj.hoverActionData = ((FancyMessage) hoverActionData).clone();
|
||||
}
|
||||
obj.translationReplacements = (ArrayList<JsonRepresentedObject>) translationReplacements.clone();
|
||||
return obj;
|
||||
|
||||
}
|
||||
|
||||
static final BiMap<ChatColor, String> stylesToNames;
|
||||
|
||||
static {
|
||||
ImmutableBiMap.Builder<ChatColor, String> builder = ImmutableBiMap.builder();
|
||||
for (final ChatColor style : ChatColor.values()) {
|
||||
if (!style.isFormat()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String styleName;
|
||||
switch (style) {
|
||||
case MAGIC:
|
||||
styleName = "obfuscated";
|
||||
break;
|
||||
case UNDERLINE:
|
||||
styleName = "underlined";
|
||||
break;
|
||||
default:
|
||||
styleName = style.name().toLowerCase();
|
||||
break;
|
||||
}
|
||||
|
||||
builder.put(style, styleName);
|
||||
}
|
||||
stylesToNames = builder.build();
|
||||
}
|
||||
|
||||
public void writeJson(JsonWriter json) {
|
||||
try {
|
||||
json.beginObject();
|
||||
text.writeJson(json);
|
||||
json.name("color").value(color.name().toLowerCase());
|
||||
for (final ChatColor style : styles) {
|
||||
json.name(stylesToNames.get(style)).value(true);
|
||||
}
|
||||
if (clickActionName != null && clickActionData != null) {
|
||||
json.name("clickEvent")
|
||||
.beginObject()
|
||||
.name("action").value(clickActionName)
|
||||
.name("value").value(clickActionData)
|
||||
.endObject();
|
||||
}
|
||||
if (hoverActionName != null && hoverActionData != null) {
|
||||
json.name("hoverEvent")
|
||||
.beginObject()
|
||||
.name("action").value(hoverActionName)
|
||||
.name("value");
|
||||
hoverActionData.writeJson(json);
|
||||
json.endObject();
|
||||
}
|
||||
if (insertionData != null) {
|
||||
json.name("insertion").value(insertionData);
|
||||
}
|
||||
if (translationReplacements.size() > 0 && text != null && TextualComponent.isTranslatableText(text)) {
|
||||
json.name("with").beginArray();
|
||||
for (JsonRepresentedObject obj : translationReplacements) {
|
||||
obj.writeJson(json);
|
||||
}
|
||||
json.endArray();
|
||||
}
|
||||
json.endObject();
|
||||
} catch (IOException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "A problem occured during writing of JSON string", e);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Object> serialize() {
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("text", text);
|
||||
map.put("styles", styles);
|
||||
map.put("color", color.getChar());
|
||||
map.put("hoverActionName", hoverActionName);
|
||||
map.put("hoverActionData", hoverActionData);
|
||||
map.put("clickActionName", clickActionName);
|
||||
map.put("clickActionData", clickActionData);
|
||||
map.put("insertion", insertionData);
|
||||
map.put("translationReplacements", translationReplacements);
|
||||
return map;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static MessagePart deserialize(Map<String, Object> serialized) {
|
||||
MessagePart part = new MessagePart((TextualComponent) serialized.get("text"));
|
||||
part.styles = (ArrayList<ChatColor>) serialized.get("styles");
|
||||
part.color = ChatColor.getByChar(serialized.get("color").toString());
|
||||
part.hoverActionName = (String) serialized.get("hoverActionName");
|
||||
part.hoverActionData = (JsonRepresentedObject) serialized.get("hoverActionData");
|
||||
part.clickActionName = (String) serialized.get("clickActionName");
|
||||
part.clickActionData = (String) serialized.get("clickActionData");
|
||||
part.insertionData = (String) serialized.get("insertion");
|
||||
part.translationReplacements = (ArrayList<JsonRepresentedObject>) serialized.get("translationReplacements");
|
||||
return part;
|
||||
}
|
||||
|
||||
static {
|
||||
ConfigurationSerialization.registerClass(MessagePart.class);
|
||||
}
|
||||
|
||||
}
|
@ -26,7 +26,9 @@ import com.sk89q.worldedit.event.platform.Interaction;
|
||||
import com.sk89q.worldedit.extension.platform.PlatformManager;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
|
||||
import com.sk89q.worldedit.util.formatting.text.TextComponent.Builder;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
@ -59,7 +61,7 @@ public class CFIPacketListener implements Listener {
|
||||
// Direct digging to the virtual world
|
||||
registerBlockEvent(PacketType.Play.Client.BLOCK_DIG, false, new RunnableVal3<PacketEvent, VirtualWorld, BlockVector3>() {
|
||||
@Override
|
||||
public void run(PacketEvent event, VirtualWorld gen, BlockVector3 pt) {
|
||||
public void run(Builder event, URI gen, String pt) {
|
||||
try {
|
||||
Player plr = event.getPlayer();
|
||||
BlockVector3 realPos = pt.add(gen.getOrigin().toBlockPoint());
|
||||
@ -75,7 +77,7 @@ public class CFIPacketListener implements Listener {
|
||||
// Direct placing to the virtual world
|
||||
RunnableVal3<PacketEvent, VirtualWorld, BlockVector3> placeTask = new RunnableVal3<PacketEvent, VirtualWorld, BlockVector3>() {
|
||||
@Override
|
||||
public void run(PacketEvent event, VirtualWorld gen, BlockVector3 pt) {
|
||||
public void run(Builder event, URI gen, String pt) {
|
||||
try {
|
||||
Player plr = event.getPlayer();
|
||||
List<EnumWrappers.Hand> hands = event.getPacket().getHands().getValues();
|
||||
@ -112,7 +114,7 @@ public class CFIPacketListener implements Listener {
|
||||
// Cancel block change packets where the real world overlaps with the virtual one
|
||||
registerBlockEvent(PacketType.Play.Server.BLOCK_CHANGE, false, new RunnableVal3<PacketEvent, VirtualWorld, BlockVector3>() {
|
||||
@Override
|
||||
public void run(PacketEvent event, VirtualWorld gen, BlockVector3 pt) {
|
||||
public void run(Builder event, URI gen, String pt) {
|
||||
// Do nothing
|
||||
}
|
||||
});
|
||||
|
@ -3,7 +3,7 @@ package com.boydti.fawe.bukkit.regions;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.regions.FaweMask;
|
||||
import com.boydti.fawe.util.Perm;
|
||||
import com.boydti.fawe.util.Permission;
|
||||
import com.massivecraft.factions.FLocation;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import org.bukkit.Chunk;
|
||||
@ -30,7 +30,8 @@ public class FactionsOneFeature extends BukkitMaskManager implements Listener {
|
||||
public FaweMask getMask(final FawePlayer<Player> fp, MaskType type) {
|
||||
final Player player = fp.parent;
|
||||
final Chunk chunk = player.getLocation().getChunk();
|
||||
final boolean perm = Perm.hasPermission(FawePlayer.wrap(player), "fawe.factions.wilderness");
|
||||
final boolean perm = Permission
|
||||
.hasPermission(fp.toWorldEditPlayer(), "fawe.factions.wilderness");
|
||||
final World world = player.getWorld();
|
||||
|
||||
RegionWrapper locs = new RegionWrapper(chunk.getX(), chunk.getX(), chunk.getZ(), chunk.getZ());
|
||||
@ -40,7 +41,7 @@ public class FactionsOneFeature extends BukkitMaskManager implements Listener {
|
||||
if (this.isAdded(locs, world, player, perm, type)) {
|
||||
boolean hasPerm = true;
|
||||
|
||||
while (hasPerm && (count > 0)) {
|
||||
while (hasPerm && count > 0) {
|
||||
count--;
|
||||
|
||||
hasPerm = false;
|
||||
|
@ -4,7 +4,7 @@ import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.regions.FaweMask;
|
||||
import com.boydti.fawe.util.Perm;
|
||||
import com.boydti.fawe.util.Permission;
|
||||
import com.massivecraft.factions.Board;
|
||||
import com.massivecraft.factions.FLocation;
|
||||
import com.massivecraft.factions.Faction;
|
||||
@ -28,7 +28,8 @@ public class FactionsUUIDFeature extends BukkitMaskManager implements Listener {
|
||||
public FaweMask getMask(final FawePlayer<Player> fp, MaskType type) {
|
||||
final Player player = fp.parent;
|
||||
final Chunk chunk = player.getLocation().getChunk();
|
||||
final boolean perm = Perm.hasPermission(FawePlayer.wrap(player), "fawe.factions.wilderness");
|
||||
final boolean perm = Permission
|
||||
.hasPermission(fp.toWorldEditPlayer(), "fawe.factions.wilderness");
|
||||
final World world = player.getWorld();
|
||||
|
||||
RegionWrapper locs = new RegionWrapper(chunk.getX(), chunk.getX(), chunk.getZ(), chunk.getZ());
|
||||
@ -38,7 +39,7 @@ public class FactionsUUIDFeature extends BukkitMaskManager implements Listener {
|
||||
if (this.isAdded(locs, world, player, perm, type)) {
|
||||
boolean hasPerm = true;
|
||||
|
||||
while (hasPerm && (count > 0)) {
|
||||
while (hasPerm && count > 0) {
|
||||
count--;
|
||||
|
||||
hasPerm = false;
|
||||
|
@ -1,15 +1,15 @@
|
||||
package com.boydti.fawe.bukkit.wrapper.state;
|
||||
|
||||
import com.boydti.fawe.bukkit.chat.FancyMessage;
|
||||
import com.boydti.fawe.bukkit.wrapper.AsyncBlock;
|
||||
import com.boydti.fawe.bukkit.wrapper.AsyncBlockState;
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||
import com.sk89q.worldedit.util.formatting.text.serializer.gson.GsonComponentSerializer;
|
||||
import com.sk89q.worldedit.util.formatting.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.server.v1_14_R1.TileEntitySign;
|
||||
import org.bukkit.DyeColor;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
@ -37,18 +37,18 @@ public class AsyncSign extends AsyncBlockState implements Sign {
|
||||
|
||||
private String fromJson(String jsonInput) {
|
||||
if (jsonInput == null || jsonInput.isEmpty()) return "";
|
||||
return FancyMessage.deserialize(jsonInput).toOldMessageFormat();
|
||||
return GsonComponentSerializer.INSTANCE.deserialize(jsonInput).toString();
|
||||
}
|
||||
|
||||
private String toJson(String oldInput) {
|
||||
if (oldInput == null || oldInput.isEmpty()) return "";
|
||||
return new FancyMessage("").color(oldInput).toJSONString();
|
||||
return LegacyComponentSerializer.INSTANCE.serialize(TextComponent.of(oldInput));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLine(int index) throws IndexOutOfBoundsException {
|
||||
CompoundTag nbt = getNbtData();
|
||||
return nbt == null ? null : fromJson(nbt.getString("Text" + (index + 1)));
|
||||
return nbt == null ? "" : fromJson(nbt.getString("Text" + (index + 1)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -80,7 +80,7 @@ public class AsyncSign extends AsyncBlockState implements Sign {
|
||||
CompoundTag nbt = getNbtData();
|
||||
if (nbt != null) {
|
||||
String color = nbt.getString("Color").toUpperCase();
|
||||
if (color != null) return DyeColor.valueOf(color);
|
||||
return DyeColor.valueOf(color);
|
||||
}
|
||||
return DyeColor.BLACK;
|
||||
}
|
||||
|
Reference in New Issue
Block a user