mirror of
https://github.com/PlaceholderAPI/PlaceholderAPI
synced 2025-02-05 15:55:28 +01:00
Switch back to the official JSONMessages
This commit is contained in:
parent
3e396a97b0
commit
0634a9cd9b
9
pom.xml
9
pom.xml
@ -24,6 +24,10 @@
|
|||||||
<id>CodeMC</id>
|
<id>CodeMC</id>
|
||||||
<url>https://repo.codemc.org/repository/maven-public</url>
|
<url>https://repo.codemc.org/repository/maven-public</url>
|
||||||
</repository>
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>rayzr-repo</id>
|
||||||
|
<url>https://rayzr.dev/repo/</url>
|
||||||
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@ -43,6 +47,11 @@
|
|||||||
<artifactId>bstats-bukkit</artifactId>
|
<artifactId>bstats-bukkit</artifactId>
|
||||||
<version>1.5</version>
|
<version>1.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>me.rayzr522</groupId>
|
||||||
|
<artifactId>jsonmessage</artifactId>
|
||||||
|
<version>1.2.1</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jetbrains</groupId>
|
<groupId>org.jetbrains</groupId>
|
||||||
<artifactId>annotations</artifactId>
|
<artifactId>annotations</artifactId>
|
||||||
|
@ -3,8 +3,8 @@ package me.clip.placeholderapi.commands.command.ecloud;
|
|||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import me.clip.placeholderapi.commands.Command;
|
import me.clip.placeholderapi.commands.Command;
|
||||||
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
||||||
import me.clip.placeholderapi.util.JSONMessage;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
import me.clip.placeholderapi.util.Msg;
|
||||||
|
import me.rayzr522.jsonmessage.JSONMessage;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
@ -4,8 +4,8 @@ import com.google.common.collect.Sets;
|
|||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import me.clip.placeholderapi.commands.Command;
|
import me.clip.placeholderapi.commands.Command;
|
||||||
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
||||||
import me.clip.placeholderapi.util.JSONMessage;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
import me.clip.placeholderapi.util.Msg;
|
||||||
|
import me.rayzr522.jsonmessage.JSONMessage;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.util.StringUtil;
|
import org.bukkit.util.StringUtil;
|
||||||
|
@ -4,8 +4,8 @@ import me.clip.placeholderapi.PlaceholderAPI;
|
|||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import me.clip.placeholderapi.commands.Command;
|
import me.clip.placeholderapi.commands.Command;
|
||||||
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
||||||
import me.clip.placeholderapi.util.JSONMessage;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
import me.clip.placeholderapi.util.Msg;
|
||||||
|
import me.rayzr522.jsonmessage.JSONMessage;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
@ -3,8 +3,8 @@ package me.clip.placeholderapi.commands.command.ecloud;
|
|||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import me.clip.placeholderapi.commands.Command;
|
import me.clip.placeholderapi.commands.Command;
|
||||||
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
||||||
import me.clip.placeholderapi.util.JSONMessage;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
import me.clip.placeholderapi.util.Msg;
|
||||||
|
import me.rayzr522.jsonmessage.JSONMessage;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
@ -1,985 +0,0 @@
|
|||||||
package me.clip.placeholderapi.util;
|
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
|
||||||
import com.google.common.collect.BiMap;
|
|
||||||
import com.google.common.collect.ImmutableBiMap;
|
|
||||||
import com.google.gson.JsonArray;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.JsonPrimitive;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a complete JSON message builder class. To create a new JSONMessage do
|
|
||||||
* {@link #create(String)}
|
|
||||||
*
|
|
||||||
* @author Rayzr
|
|
||||||
*/
|
|
||||||
@SuppressWarnings({"WeakerAccess", "unused"})
|
|
||||||
public class JSONMessage {
|
|
||||||
private 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private final List<MessagePart> parts = new ArrayList<>();
|
|
||||||
private int centeringStartIndex = -1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link JSONMessage} object
|
|
||||||
*
|
|
||||||
* @param text The text to start with
|
|
||||||
*/
|
|
||||||
private JSONMessage(String text) {
|
|
||||||
parts.add(new MessagePart(text));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link JSONMessage} object
|
|
||||||
*
|
|
||||||
* @param text The text to start with
|
|
||||||
* @return A new {@link JSONMessage} object
|
|
||||||
*/
|
|
||||||
public static JSONMessage create(String text) {
|
|
||||||
return new JSONMessage(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link JSONMessage} object
|
|
||||||
*
|
|
||||||
* @return A new {@link JSONMessage} object
|
|
||||||
*/
|
|
||||||
public static JSONMessage create() {
|
|
||||||
return create("");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends an action bar message
|
|
||||||
*
|
|
||||||
* @param message The message to send
|
|
||||||
* @param players The players you want to send it to
|
|
||||||
*/
|
|
||||||
public static void actionbar(String message, Player... players) {
|
|
||||||
ReflectionHelper.sendPacket(ReflectionHelper.createActionbarPacket(ChatColor.translateAlternateColorCodes('&', message)), players);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The latest {@link MessagePart}
|
|
||||||
* @throws ArrayIndexOutOfBoundsException If {@code parts.size() <= 0}.
|
|
||||||
*/
|
|
||||||
public MessagePart last() {
|
|
||||||
if (parts.size() <= 0) {
|
|
||||||
throw new ArrayIndexOutOfBoundsException("No MessageParts exist!");
|
|
||||||
}
|
|
||||||
return parts.get(parts.size() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts this {@link JSONMessage} instance to actual JSON
|
|
||||||
*
|
|
||||||
* @return The JSON representation of this {@link JSONMessage}
|
|
||||||
*/
|
|
||||||
public JsonObject toJSON() {
|
|
||||||
JsonObject obj = new JsonObject();
|
|
||||||
|
|
||||||
obj.addProperty("text", "");
|
|
||||||
|
|
||||||
JsonArray array = new JsonArray();
|
|
||||||
|
|
||||||
parts.stream()
|
|
||||||
.map(MessagePart::toJSON)
|
|
||||||
.forEach(array::add);
|
|
||||||
|
|
||||||
obj.add("extra", array);
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts this {@link JSONMessage} object to a String representation of the JSON.
|
|
||||||
* This is an alias of {@code toJSON().toString()}.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return toJSON().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts this {@link JSONMessage} object to the legacy formatting system, which
|
|
||||||
* uses formatting codes (like &6, &l, &4, etc.)
|
|
||||||
*
|
|
||||||
* @return This {@link JSONMessage} instance {@link JSONMessage} in legacy format
|
|
||||||
*/
|
|
||||||
public String toLegacy() {
|
|
||||||
StringBuilder output = new StringBuilder();
|
|
||||||
|
|
||||||
parts.stream()
|
|
||||||
.map(MessagePart::toLegacy)
|
|
||||||
.forEach(output::append);
|
|
||||||
|
|
||||||
return output.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends this {@link JSONMessage} to all the players specified
|
|
||||||
*
|
|
||||||
* @param players The players you want to send this to
|
|
||||||
*/
|
|
||||||
public void send(Player... players) {
|
|
||||||
if (ReflectionHelper.getStringVersion().equalsIgnoreCase("v1_16_R1")) {
|
|
||||||
ReflectionHelper.sendTextPacket(toString(), players);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReflectionHelper.sendPacket(ReflectionHelper.createTextPacket(toString()), players);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends this as a title to all the players specified
|
|
||||||
*
|
|
||||||
* @param fadeIn How many ticks to fade in
|
|
||||||
* @param stay How many ticks to stay
|
|
||||||
* @param fadeOut How many ticks to fade out
|
|
||||||
* @param players The players to send this to
|
|
||||||
*/
|
|
||||||
public void title(int fadeIn, int stay, int fadeOut, Player... players) {
|
|
||||||
ReflectionHelper.sendPacket(ReflectionHelper.createTitleTimesPacket(fadeIn, stay, fadeOut), players);
|
|
||||||
ReflectionHelper.sendPacket(ReflectionHelper.createTitlePacket(toString()), players);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends this as a subtitle to all the players specified. Must be used after sending a {@link #title(int, int, int, Player...) title}.
|
|
||||||
*
|
|
||||||
* @param players The players to send this to
|
|
||||||
*/
|
|
||||||
public void subtitle(Player... players) {
|
|
||||||
ReflectionHelper.sendPacket(ReflectionHelper.createSubtitlePacket(toString()), players);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends an action bar message
|
|
||||||
*
|
|
||||||
* @param players The players you want to send this to
|
|
||||||
*/
|
|
||||||
public void actionbar(Player... players) {
|
|
||||||
actionbar(toLegacy(), players);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the color of the current message part.
|
|
||||||
*
|
|
||||||
* @param color The color to set
|
|
||||||
* @return This {@link JSONMessage} instance
|
|
||||||
*/
|
|
||||||
public JSONMessage color(ChatColor color) {
|
|
||||||
last().setColor(color);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a style to the current message part.
|
|
||||||
*
|
|
||||||
* @param style The style to add
|
|
||||||
* @return This {@link JSONMessage} instance
|
|
||||||
*/
|
|
||||||
public JSONMessage style(ChatColor style) {
|
|
||||||
last().addStyle(style);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the text run a command.
|
|
||||||
*
|
|
||||||
* @param command The command to run
|
|
||||||
* @return This {@link JSONMessage} instance
|
|
||||||
*/
|
|
||||||
public JSONMessage runCommand(String command) {
|
|
||||||
last().setOnClick(ClickEvent.runCommand(command));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the text suggest a command.
|
|
||||||
*
|
|
||||||
* @param command The command to suggest
|
|
||||||
* @return This {@link JSONMessage} instance
|
|
||||||
*/
|
|
||||||
public JSONMessage suggestCommand(String command) {
|
|
||||||
last().setOnClick(ClickEvent.suggestCommand(command));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens a URL.
|
|
||||||
*
|
|
||||||
* @param url The url to open
|
|
||||||
* @return This {@link JSONMessage} instance
|
|
||||||
*/
|
|
||||||
public JSONMessage openURL(String url) {
|
|
||||||
last().setOnClick(ClickEvent.openURL(url));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the page of a book. Using this in a non-book context is useless
|
|
||||||
* and will probably error.
|
|
||||||
*
|
|
||||||
* @param page The page to change to
|
|
||||||
* @return This {@link JSONMessage} instance
|
|
||||||
*/
|
|
||||||
public JSONMessage changePage(int page) {
|
|
||||||
last().setOnClick(ClickEvent.changePage(page));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows text when you hover over it
|
|
||||||
*
|
|
||||||
* @param text The text to show
|
|
||||||
* @return This {@link JSONMessage} instance
|
|
||||||
*/
|
|
||||||
public JSONMessage tooltip(String text) {
|
|
||||||
last().setOnHover(HoverEvent.showText(text));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows text when you hover over it
|
|
||||||
*
|
|
||||||
* @param message The text to show
|
|
||||||
* @return This {@link JSONMessage} instance
|
|
||||||
*/
|
|
||||||
public JSONMessage tooltip(JSONMessage message) {
|
|
||||||
last().setOnHover(HoverEvent.showText(message));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows an achievement when you hover over it
|
|
||||||
*
|
|
||||||
* @param id The id of the achievement
|
|
||||||
* @return This {@link JSONMessage} instance
|
|
||||||
*/
|
|
||||||
public JSONMessage achievement(String id) {
|
|
||||||
last().setOnHover(HoverEvent.showAchievement(id));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds another part to this {@link JSONMessage}
|
|
||||||
*
|
|
||||||
* @param text The text to start the next {@link MessagePart} with
|
|
||||||
* @return This {@link JSONMessage} instance
|
|
||||||
*/
|
|
||||||
public JSONMessage then(String text) {
|
|
||||||
return then(new MessagePart(text));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds another part to this {@link JSONMessage}
|
|
||||||
*
|
|
||||||
* @param nextPart The next {@link MessagePart}
|
|
||||||
* @return This {@link JSONMessage} instance
|
|
||||||
*/
|
|
||||||
public JSONMessage then(MessagePart nextPart) {
|
|
||||||
parts.add(nextPart);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a horizontal bar to the message of the given length
|
|
||||||
*
|
|
||||||
* @param length The length of the horizontal bar
|
|
||||||
* @return This {@link JSONMessage} instance
|
|
||||||
*/
|
|
||||||
public JSONMessage bar(int length) {
|
|
||||||
return then(Strings.repeat("-", length)).color(ChatColor.DARK_GRAY).style(ChatColor.STRIKETHROUGH);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a horizontal bar to the message that's 53 characters long. This is
|
|
||||||
* the default width of the player's chat window.
|
|
||||||
*
|
|
||||||
* @return This {@link JSONMessage} instance
|
|
||||||
*/
|
|
||||||
public JSONMessage bar() {
|
|
||||||
return bar(53);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a blank line to the message
|
|
||||||
*
|
|
||||||
* @return This {@link JSONMessage} instance
|
|
||||||
*/
|
|
||||||
public JSONMessage newline() {
|
|
||||||
return then("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the starting point to begin centering JSONMessages.
|
|
||||||
*
|
|
||||||
* @return This {@link JSONMessage} instance
|
|
||||||
*/
|
|
||||||
public JSONMessage beginCenter() {
|
|
||||||
// Start with the NEXT message part.
|
|
||||||
centeringStartIndex = parts.size();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ends the centering of the JSONMessage text.
|
|
||||||
*
|
|
||||||
* @return This {@link JSONMessage} instance
|
|
||||||
*/
|
|
||||||
public JSONMessage endCenter() {
|
|
||||||
int current = centeringStartIndex;
|
|
||||||
|
|
||||||
while (current < parts.size()) {
|
|
||||||
Vector<MessagePart> currentLine = new Vector<>();
|
|
||||||
int totalLineLength = 0;
|
|
||||||
|
|
||||||
for (; ; current++) {
|
|
||||||
MessagePart part = current < parts.size() ? parts.get(current) : null;
|
|
||||||
String raw = part == null ? null : ChatColor.stripColor(part.toLegacy());
|
|
||||||
|
|
||||||
if (current >= parts.size() || totalLineLength + raw.length() >= 53) {
|
|
||||||
int padding = Math.max(0, (53 - totalLineLength) / 2);
|
|
||||||
currentLine.firstElement().setText(Strings.repeat(" ", padding) + currentLine.firstElement().getText());
|
|
||||||
currentLine.lastElement().setText(currentLine.lastElement().getText() + "\n");
|
|
||||||
currentLine.clear();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
totalLineLength += raw.length();
|
|
||||||
currentLine.add(part);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MessagePart last = parts.get(parts.size() - 1);
|
|
||||||
last.setText(last.getText().substring(0, last.getText().length() - 1));
|
|
||||||
|
|
||||||
centeringStartIndex = -1;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////
|
|
||||||
// BEGIN UTILITY CLASSES //
|
|
||||||
///////////////////////////
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the JSON format that all click/hover events in JSON messages must follow.
|
|
||||||
* <br>
|
|
||||||
* <br>
|
|
||||||
* <a href="http://minecraft.gamepedia.com/Commands#Raw_JSON_text">Reference</a>
|
|
||||||
*
|
|
||||||
* @author Rayzr
|
|
||||||
*/
|
|
||||||
public static class MessageEvent {
|
|
||||||
|
|
||||||
private String action;
|
|
||||||
private Object value;
|
|
||||||
|
|
||||||
public MessageEvent(String action, Object value) {
|
|
||||||
this.action = action;
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return A {@link JsonObject} representing the properties of this {@link MessageEvent}
|
|
||||||
*/
|
|
||||||
public JsonObject toJSON() {
|
|
||||||
JsonObject obj = new JsonObject();
|
|
||||||
obj.addProperty("action", action);
|
|
||||||
if (value instanceof JsonElement) {
|
|
||||||
obj.add("value", (JsonElement) value);
|
|
||||||
} else {
|
|
||||||
obj.addProperty("value", value.toString());
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The action
|
|
||||||
*/
|
|
||||||
public String getAction() {
|
|
||||||
return action;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param action The action to set
|
|
||||||
*/
|
|
||||||
public void setAction(String action) {
|
|
||||||
this.action = action;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The value
|
|
||||||
*/
|
|
||||||
public Object getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param value The value to set
|
|
||||||
*/
|
|
||||||
public void setValue(Object value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ClickEvent {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs a command.
|
|
||||||
*
|
|
||||||
* @param command The command to run
|
|
||||||
* @return The {@link MessageEvent}
|
|
||||||
*/
|
|
||||||
public static MessageEvent runCommand(String command) {
|
|
||||||
return new MessageEvent("run_command", command);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Suggests a command by putting inserting it in chat.
|
|
||||||
*
|
|
||||||
* @param command The command to suggest
|
|
||||||
* @return The {@link MessageEvent}
|
|
||||||
*/
|
|
||||||
public static MessageEvent suggestCommand(String command) {
|
|
||||||
return new MessageEvent("suggest_command", command);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Requires web links to be enabled on the client.
|
|
||||||
*
|
|
||||||
* @param url The url to open
|
|
||||||
* @return The {@link MessageEvent}
|
|
||||||
*/
|
|
||||||
public static MessageEvent openURL(String url) {
|
|
||||||
return new MessageEvent("open_url", url);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Only used with written books.
|
|
||||||
*
|
|
||||||
* @param page The page to switch to
|
|
||||||
* @return The {@link MessageEvent}
|
|
||||||
*/
|
|
||||||
public static MessageEvent changePage(int page) {
|
|
||||||
return new MessageEvent("change_page", page);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class HoverEvent {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows text when you hover over it
|
|
||||||
*
|
|
||||||
* @param text The text to show
|
|
||||||
* @return The {@link MessageEvent}
|
|
||||||
*/
|
|
||||||
public static MessageEvent showText(String text) {
|
|
||||||
return new MessageEvent("show_text", text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows text when you hover over it
|
|
||||||
*
|
|
||||||
* @param message The {@link JSONMessage} to show
|
|
||||||
* @return The {@link MessageEvent}
|
|
||||||
*/
|
|
||||||
public static MessageEvent showText(JSONMessage message) {
|
|
||||||
JsonArray arr = new JsonArray();
|
|
||||||
arr.add(new JsonPrimitive(""));
|
|
||||||
arr.add(message.toJSON());
|
|
||||||
return new MessageEvent("show_text", arr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows an achievement when you hover over it
|
|
||||||
*
|
|
||||||
* @param id The id of the achievement
|
|
||||||
* @return The {@link MessageEvent}
|
|
||||||
*/
|
|
||||||
public static MessageEvent showAchievement(String id) {
|
|
||||||
return new MessageEvent("show_achievement", id);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ReflectionHelper {
|
|
||||||
|
|
||||||
private static final String version;
|
|
||||||
private static Class<?> craftPlayer;
|
|
||||||
private static Constructor<?> chatComponentText;
|
|
||||||
private static Class<?> packetPlayOutChat;
|
|
||||||
private static Class<?> packetPlayOutTitle;
|
|
||||||
private static Class<?> iChatBaseComponent;
|
|
||||||
private static Class<?> titleAction;
|
|
||||||
private static Field connection;
|
|
||||||
private static MethodHandle GET_HANDLE;
|
|
||||||
private static MethodHandle SEND_PACKET;
|
|
||||||
private static MethodHandle STRING_TO_CHAT;
|
|
||||||
private static Object enumActionTitle;
|
|
||||||
private static Object enumActionSubtitle;
|
|
||||||
private static Object enumChatMessage;
|
|
||||||
private static Object enumActionbarMessage;
|
|
||||||
private static boolean SETUP;
|
|
||||||
private static int MAJOR_VER = -1;
|
|
||||||
|
|
||||||
static {
|
|
||||||
String[] split = Bukkit.getServer().getClass().getPackage().getName().split("\\.");
|
|
||||||
version = split[split.length - 1];
|
|
||||||
|
|
||||||
try {
|
|
||||||
SETUP = true;
|
|
||||||
|
|
||||||
MAJOR_VER = getVersion();
|
|
||||||
|
|
||||||
craftPlayer = getClass("{obc}.entity.CraftPlayer");
|
|
||||||
Method getHandle = craftPlayer.getMethod("getHandle");
|
|
||||||
connection = getHandle.getReturnType().getField("playerConnection");
|
|
||||||
Method sendPacket = connection.getType().getMethod("sendPacket", getClass("{nms}.Packet"));
|
|
||||||
|
|
||||||
chatComponentText = getClass("{nms}.ChatComponentText").getConstructor(String.class);
|
|
||||||
|
|
||||||
iChatBaseComponent = getClass("{nms}.IChatBaseComponent");
|
|
||||||
|
|
||||||
Method stringToChat;
|
|
||||||
|
|
||||||
if (MAJOR_VER < 8) {
|
|
||||||
stringToChat = getClass("{nms}.ChatSerializer").getMethod("a", String.class);
|
|
||||||
} else {
|
|
||||||
stringToChat = getClass("{nms}.IChatBaseComponent$ChatSerializer").getMethod("a", String.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
GET_HANDLE = MethodHandles.lookup().unreflect(getHandle);
|
|
||||||
SEND_PACKET = MethodHandles.lookup().unreflect(sendPacket);
|
|
||||||
STRING_TO_CHAT = MethodHandles.lookup().unreflect(stringToChat);
|
|
||||||
|
|
||||||
packetPlayOutChat = getClass("{nms}.PacketPlayOutChat");
|
|
||||||
packetPlayOutTitle = getClass("{nms}.PacketPlayOutTitle");
|
|
||||||
|
|
||||||
titleAction = getClass("{nms}.PacketPlayOutTitle$EnumTitleAction");
|
|
||||||
|
|
||||||
enumActionTitle = titleAction.getField("TITLE").get(null);
|
|
||||||
enumActionSubtitle = titleAction.getField("SUBTITLE").get(null);
|
|
||||||
|
|
||||||
if (MAJOR_VER >= 12) {
|
|
||||||
Method getChatMessageType = getClass("{nms}.ChatMessageType").getMethod("a", byte.class);
|
|
||||||
|
|
||||||
enumChatMessage = getChatMessageType.invoke(null, (byte) 1);
|
|
||||||
enumActionbarMessage = getChatMessageType.invoke(null, (byte) 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
SETUP = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sendPacket(Object packet, Player... players) {
|
|
||||||
if (!SETUP) {
|
|
||||||
throw new IllegalStateException("ReflectionHelper is not set up!");
|
|
||||||
}
|
|
||||||
if (packet == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Player player : players) {
|
|
||||||
try {
|
|
||||||
SEND_PACKET.bindTo(connection.get(GET_HANDLE.bindTo(player).invoke())).invoke(packet);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
System.err.println("Failed to send packet");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void setType(Object object, byte type) {
|
|
||||||
if (MAJOR_VER < 12) {
|
|
||||||
set("b", object, type);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case 1:
|
|
||||||
set("b", object, enumChatMessage);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
set("b", object, enumActionbarMessage);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("type must be 1 or 2");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static Object createActionbarPacket(String message) {
|
|
||||||
if (!SETUP) {
|
|
||||||
throw new IllegalStateException("ReflectionHelper is not set up!");
|
|
||||||
}
|
|
||||||
Object packet = createTextPacket(message);
|
|
||||||
setType(packet, (byte) 2);
|
|
||||||
return packet;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Object createTextPacket(String message) {
|
|
||||||
if (!SETUP) {
|
|
||||||
throw new IllegalStateException("ReflectionHelper is not set up!");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Object packet = packetPlayOutChat.newInstance();
|
|
||||||
set("a", packet, fromJson(message));
|
|
||||||
setType(packet, (byte) 1);
|
|
||||||
return packet;
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sendTextPacket(String message, Player... players) {
|
|
||||||
try {
|
|
||||||
for (Player player : players) {
|
|
||||||
Class chatTypeClass = getClass("{nms}.ChatMessageType");
|
|
||||||
Constructor<?> constructor = packetPlayOutChat.getConstructor(getClass("{nms}.IChatBaseComponent"), chatTypeClass, UUID.class);
|
|
||||||
Object packet = constructor.newInstance(fromJson(message), Enum.valueOf(chatTypeClass, "CHAT"), player.getUniqueId());
|
|
||||||
|
|
||||||
Object handler = player.getClass().getMethod("getHandle").invoke(player);
|
|
||||||
Object playerConnection = handler.getClass().getField("playerConnection").get(handler);
|
|
||||||
playerConnection.getClass().getMethod("sendPacket", getClass("{nms}.Packet")).invoke(playerConnection, packet);
|
|
||||||
}
|
|
||||||
} catch (IllegalArgumentException | NoSuchMethodException | NoSuchFieldException | IllegalAccessException | InvocationTargetException | InstantiationException | ClassNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static Object createTitlePacket(String message) {
|
|
||||||
if (!SETUP) {
|
|
||||||
throw new IllegalStateException("ReflectionHelper is not set up!");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return packetPlayOutTitle.getConstructor(titleAction, iChatBaseComponent).newInstance(enumActionTitle, fromJson(message));
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static Object createSubtitlePacket(String message) {
|
|
||||||
if (!SETUP) {
|
|
||||||
throw new IllegalStateException("ReflectionHelper is not set up!");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return packetPlayOutTitle.getConstructor(titleAction, iChatBaseComponent).newInstance(enumActionSubtitle, fromJson(message));
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static Object createTitleTimesPacket(int fadeIn, int stay, int fadeOut) {
|
|
||||||
if (!SETUP) {
|
|
||||||
throw new IllegalStateException("ReflectionHelper is not set up!");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return packetPlayOutTitle.getConstructor(int.class, int.class, int.class).newInstance(fadeIn, stay, fadeOut);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a ChatComponentText from plain text
|
|
||||||
*
|
|
||||||
* @param message The text to convert to a chat component
|
|
||||||
* @return The chat component
|
|
||||||
*/
|
|
||||||
static Object componentText(String message) {
|
|
||||||
if (!SETUP) {
|
|
||||||
throw new IllegalStateException("ReflectionHelper is not set up!");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return chatComponentText.newInstance(message);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempts to convert a String representing a JSON message into a usable object
|
|
||||||
*
|
|
||||||
* @param json The JSON to attempt to parse
|
|
||||||
* @return The object representing the text in JSON form, or <code>null</code> if something went wrong converting the String to JSON data
|
|
||||||
*/
|
|
||||||
static Object fromJson(String json) {
|
|
||||||
if (!SETUP) {
|
|
||||||
throw new IllegalStateException("ReflectionHelper is not set up!");
|
|
||||||
}
|
|
||||||
if (!json.trim().startsWith("{")) {
|
|
||||||
return componentText(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return STRING_TO_CHAT.invoke(json);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a class with the given package and name. This method replaces <code>{nms}</code> with <code>net.minecraft.server.[version]</code> and <code>{obc}</code> with <code>org.bukkit.craft.[version]</code>
|
|
||||||
* <br>
|
|
||||||
* <br>
|
|
||||||
* Example:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* Class<?> entityPlayer = ReflectionHelper.getClass("{nms}.EntityPlayer");
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @param path The path to the {@link Class}
|
|
||||||
* @return The class
|
|
||||||
* @throws ClassNotFoundException If the class was not found
|
|
||||||
*/
|
|
||||||
static Class<?> getClass(String path) throws ClassNotFoundException {
|
|
||||||
if (!SETUP) {
|
|
||||||
throw new IllegalStateException("ReflectionHelper is not set up!");
|
|
||||||
}
|
|
||||||
return Class.forName(path.replace("{nms}", "net.minecraft.server." + version).replace("{obc}", "org.bukkit.craftbukkit." + version));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a field with the given name on an object to the value specified
|
|
||||||
*
|
|
||||||
* @param field The name of the field to change
|
|
||||||
* @param obj The object to change the field of
|
|
||||||
* @param value The new value to set
|
|
||||||
*/
|
|
||||||
static void set(String field, Object obj, Object value) {
|
|
||||||
try {
|
|
||||||
Field f = obj.getClass().getDeclaredField(field);
|
|
||||||
f.setAccessible(true);
|
|
||||||
f.set(obj, value);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getStringVersion() {
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int getVersion() {
|
|
||||||
if (!SETUP) {
|
|
||||||
throw new IllegalStateException("ReflectionHelper is not set up!");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return Integer.parseInt(version.split("_")[1]);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines a section of the message, and represents the format that all JSON messages must follow in Minecraft.
|
|
||||||
* <br>
|
|
||||||
* <br>
|
|
||||||
* <a href="http://minecraft.gamepedia.com/Commands#Raw_JSON_text">Reference</a>
|
|
||||||
*
|
|
||||||
* @author Rayzr
|
|
||||||
*/
|
|
||||||
public static class MessagePart {
|
|
||||||
|
|
||||||
private final List<ChatColor> styles = new ArrayList<>();
|
|
||||||
private MessageEvent onClick;
|
|
||||||
private MessageEvent onHover;
|
|
||||||
private ChatColor color;
|
|
||||||
private String text;
|
|
||||||
|
|
||||||
public MessagePart(String text) {
|
|
||||||
this.text = text == null ? "null" : text;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts this {@link MessagePart} into a {@link JsonObject}
|
|
||||||
*
|
|
||||||
* @return The Minecraft-compatible {@link JsonObject}
|
|
||||||
*/
|
|
||||||
public JsonObject toJSON() {
|
|
||||||
Objects.requireNonNull(text);
|
|
||||||
|
|
||||||
JsonObject obj = new JsonObject();
|
|
||||||
obj.addProperty("text", text);
|
|
||||||
|
|
||||||
if (color != null) {
|
|
||||||
obj.addProperty("color", color.name().toLowerCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ChatColor style : styles) {
|
|
||||||
obj.addProperty(stylesToNames.get(style), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (onClick != null) {
|
|
||||||
obj.add("clickEvent", onClick.toJSON());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (onHover != null) {
|
|
||||||
obj.add("hoverEvent", onHover.toJSON());
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return This {@link MessagePart} in legacy-style color/formatting codes
|
|
||||||
*/
|
|
||||||
public String toLegacy() {
|
|
||||||
StringBuilder output = new StringBuilder();
|
|
||||||
if (color != null) {
|
|
||||||
output.append(color.toString());
|
|
||||||
}
|
|
||||||
styles.stream()
|
|
||||||
.map(ChatColor::toString)
|
|
||||||
.forEach(output::append);
|
|
||||||
|
|
||||||
return output.append(text).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The click event bound
|
|
||||||
*/
|
|
||||||
public MessageEvent getOnClick() {
|
|
||||||
return onClick;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param onClick The new click event to bind
|
|
||||||
*/
|
|
||||||
public void setOnClick(MessageEvent onClick) {
|
|
||||||
this.onClick = onClick;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The hover event bound
|
|
||||||
*/
|
|
||||||
public MessageEvent getOnHover() {
|
|
||||||
return onHover;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param onHover The new hover event to bind
|
|
||||||
*/
|
|
||||||
public void setOnHover(MessageEvent onHover) {
|
|
||||||
this.onHover = onHover;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The color
|
|
||||||
*/
|
|
||||||
public ChatColor getColor() {
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param color The color to set
|
|
||||||
*/
|
|
||||||
public void setColor(ChatColor color) {
|
|
||||||
if (!color.isColor()) {
|
|
||||||
throw new IllegalArgumentException(color.name() + " is not a color!");
|
|
||||||
}
|
|
||||||
this.color = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The list of styles
|
|
||||||
*/
|
|
||||||
public List<ChatColor> getStyles() {
|
|
||||||
return styles;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param style The new style to add
|
|
||||||
*/
|
|
||||||
public void addStyle(ChatColor style) {
|
|
||||||
if (style == null) {
|
|
||||||
throw new IllegalArgumentException("Style cannot be null!");
|
|
||||||
}
|
|
||||||
if (!style.isFormat()) {
|
|
||||||
throw new IllegalArgumentException(color.name() + " is not a style!");
|
|
||||||
}
|
|
||||||
styles.add(style);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The raw text
|
|
||||||
*/
|
|
||||||
public String getText() {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param text The raw text to set
|
|
||||||
*/
|
|
||||||
public void setText(String text) {
|
|
||||||
this.text = text;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user