Added support for hex codes and a slight rewrite for locale.

This commit is contained in:
Brianna 2020-06-26 21:11:44 -05:00
parent a756deded1
commit 6f7ffe7bb5
14 changed files with 551 additions and 228 deletions

View File

@ -0,0 +1,254 @@
package com.songoda.core.chat;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.core.utils.TextUtils;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
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.Collections;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ChatMessage {
private static final Gson gson = new GsonBuilder().create();
private List<JsonObject> textList = new ArrayList<>();
public void clear() {
textList.clear();
}
public ChatMessage fromText(String text) {
Pattern pattern = Pattern.compile("(.*?)(?!&(o|m|n|l|k))(?=(\\&(1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|r|#)|$)|"
+ "#([a-f]|[A-F]|[0-9]){6})", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
ColorContainer color = null;
String match1 = matcher.group(1);
if (matcher.groupCount() == 0 || match1.length() == 0) continue;
char colorChar = '-';
int charPos = matcher.start() - 1;
if (charPos != -1)
colorChar = text.substring(matcher.start() - 1, matcher.start()).charAt(0);
if (colorChar != '-') {
if (colorChar == '#') {
color = new ColorContainer(match1.substring(0, 6));
match1 = match1.substring(5);
} else if (colorChar == '&')
color = new ColorContainer(ColorCode.getByChar(match1.charAt(0)));
}
if (color != null && color.getColorCode() == ColorCode.RESET) color = null;
Pattern subPattern = Pattern.compile("(.*?)(?=\\&(o|m|n|l|k)|$)");
Matcher subMatcher = subPattern.matcher(match1);
List<ColorCode> stackedCodes = new ArrayList<>();
while (subMatcher.find()) {
String match2 = subMatcher.group(1);
if (match2.length() == 0) continue;
ColorCode code = ColorCode.getByChar(match2.charAt(0));
if (code != null)
stackedCodes.add(code);
if (color != null)
match2 = match2.substring(1);
if (match2.length() == 0) continue;
addMessage(match2, color, stackedCodes);
}
}
return this;
}
public String toText() {
StringBuilder text = new StringBuilder();
for (JsonObject object : textList) {
if (object.has("color")) {
String color = object.get("color").getAsString();
text.append("&");
if (color.length() == 7) {
text.append(new ColorContainer(color).getColor().getCode());
} else {
text.append(ColorCode.valueOf(color.toUpperCase()).getCode());
}
}
for (ColorCode code : ColorCode.values()) {
if (code.isColor()) continue;
String c = code.name().toLowerCase();
if (object.has(c) && object.get(c).getAsBoolean())
text.append("&").append(code.getCode());
}
text.append(object.get("text").getAsString());
}
return "&r" + text.toString();
}
public ChatMessage addMessage(String s) {
JsonObject txt = new JsonObject();
txt.addProperty("text", s);
textList.add(txt);
return this;
}
public ChatMessage addMessage(String text, ColorContainer color) {
return addMessage(text, color, Collections.emptyList());
}
public ChatMessage addMessage(String text, ColorContainer color, List<ColorCode> colorCodes) {
JsonObject txt = new JsonObject();
txt.addProperty("text", text);
if (color != null)
txt.addProperty("color", color.getHexCode() != null ? "#" + color.getHexCode() : color.getColorCode().name().toLowerCase());
for (ColorCode code : ColorCode.values()) {
if (!code.isColor())
txt.addProperty(code.name().toLowerCase(), colorCodes.contains(code));
}
textList.add(txt);
return this;
}
public ChatMessage addRunCommand(String text, String hoverText, String cmd) {
JsonObject txt = new JsonObject();
txt.addProperty("text", text);
JsonObject hover = new JsonObject();
hover.addProperty("action", "show_text");
hover.addProperty("value", hoverText);
txt.add("hoverEvent", hover);
JsonObject click = new JsonObject();
click.addProperty("action", "run_command");
click.addProperty("value", cmd);
txt.add("clickEvent", click);
textList.add(txt);
return this;
}
public ChatMessage addPromptCommand(String text, String hoverText, String cmd) {
JsonObject txt = new JsonObject();
txt.addProperty("text", text);
JsonObject hover = new JsonObject();
hover.addProperty("action", "show_text");
hover.addProperty("value", hoverText);
txt.add("hoverEvent", hover);
JsonObject click = new JsonObject();
click.addProperty("action", "suggest_command");
click.addProperty("value", cmd);
txt.add("clickEvent", click);
textList.add(txt);
return this;
}
public ChatMessage addURL(String text, String hoverText, String url) {
JsonObject txt = new JsonObject();
txt.addProperty("text", text);
JsonObject hover = new JsonObject();
hover.addProperty("action", "show_text");
hover.addProperty("value", hoverText);
txt.add("hoverEvent", hover);
JsonObject click = new JsonObject();
click.addProperty("action", "open_url");
click.addProperty("value", url);
txt.add("clickEvent", hover);
textList.add(txt);
return this;
}
@Override
public String toString() {
return gson.toJson(textList);
}
public void sendTo(CommandSender sender) {
sendTo(null, sender);
}
public void sendTo(ChatMessage prefix, CommandSender sender) {
if (sender instanceof Player && enabled) {
try {
List<JsonObject> textList = prefix == null ? new ArrayList<>() : new ArrayList<>(prefix.textList);
textList.addAll(this.textList);
Object packet;
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_16)) {
packet = mc_PacketPlayOutChat_new.newInstance(mc_IChatBaseComponent_ChatSerializer_a.invoke(null, gson.toJson(textList)), mc_chatMessageType_Chat.get(null), ((Player)sender).getUniqueId());
} else {
packet = mc_PacketPlayOutChat_new.newInstance(mc_IChatBaseComponent_ChatSerializer_a.invoke(null, gson.toJson(textList)));
}
Object cbPlayer = cb_craftPlayer_getHandle.invoke(sender);
Object mcConnection = mc_entityPlayer_playerConnection.get(cbPlayer);
mc_playerConnection_sendPacket.invoke(mcConnection, packet);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
Bukkit.getLogger().log(Level.WARNING, "Problem preparing raw chat packets (disabling further packets)", ex);
enabled = false;
}
} else {
sender.sendMessage(TextUtils.formatText((prefix == null ? "" : prefix.toText() + " ") + toText()));
}
}
private static boolean enabled = ServerVersion.isServerVersionAtLeast(ServerVersion.V1_8);
private static Class<?> mc_ChatMessageType;
private static Method mc_IChatBaseComponent_ChatSerializer_a, cb_craftPlayer_getHandle, mc_playerConnection_sendPacket;
private static Constructor mc_PacketPlayOutChat_new;
private static Field mc_entityPlayer_playerConnection, mc_chatMessageType_Chat;
static {
init();
}
static void init() {
if (enabled) {
try {
final String version = ServerVersion.getServerVersionString();
Class<?> cb_craftPlayerClazz, mc_entityPlayerClazz, mc_playerConnectionClazz, mc_PacketInterface,
mc_IChatBaseComponent, mc_IChatBaseComponent_ChatSerializer, mc_PacketPlayOutChat;
cb_craftPlayerClazz = Class.forName("org.bukkit.craftbukkit." + version + ".entity.CraftPlayer");
cb_craftPlayer_getHandle = cb_craftPlayerClazz.getDeclaredMethod("getHandle");
mc_entityPlayerClazz = Class.forName("net.minecraft.server." + version + ".EntityPlayer");
mc_entityPlayer_playerConnection = mc_entityPlayerClazz.getDeclaredField("playerConnection");
mc_playerConnectionClazz = Class.forName("net.minecraft.server." + version + ".PlayerConnection");
mc_PacketInterface = Class.forName("net.minecraft.server." + version + ".Packet");
mc_playerConnection_sendPacket = mc_playerConnectionClazz.getDeclaredMethod("sendPacket", mc_PacketInterface);
mc_IChatBaseComponent = Class.forName("net.minecraft.server." + version + ".IChatBaseComponent");
mc_IChatBaseComponent_ChatSerializer = Class.forName("net.minecraft.server." + version + ".IChatBaseComponent$ChatSerializer");
mc_IChatBaseComponent_ChatSerializer_a = mc_IChatBaseComponent_ChatSerializer.getMethod("a", String.class);
mc_PacketPlayOutChat = Class.forName("net.minecraft.server." + version + ".PacketPlayOutChat");
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_16)) {
mc_ChatMessageType = Class.forName("net.minecraft.server." + version + ".ChatMessageType");
mc_chatMessageType_Chat = mc_ChatMessageType.getField("CHAT");
mc_PacketPlayOutChat_new = mc_PacketPlayOutChat.getConstructor(mc_IChatBaseComponent, mc_ChatMessageType, UUID.class);
} else {
mc_PacketPlayOutChat_new = mc_PacketPlayOutChat.getConstructor(mc_IChatBaseComponent);
}
} catch (Throwable ex) {
Bukkit.getLogger().log(Level.WARNING, "Problem preparing raw chat packets (disabling further packets)", ex);
enabled = false;
}
}
}
public ChatMessage replaceAll(String toReplace, String replaceWith) {
for (JsonObject object : textList) {
String text = object.get("text").getAsString()
.replaceAll(toReplace, replaceWith);
object.remove("text");
object.addProperty("text", text);
}
return this;
}
}

View File

@ -0,0 +1,71 @@
package com.songoda.core.chat;
import org.bukkit.ChatColor;
import java.util.HashMap;
import java.util.Map;
public enum ColorCode {
BLACK('0', ChatColor.BLACK, true),
DARK_BLUE('1', ChatColor.DARK_BLUE, true),
DARK_GREEN('2', ChatColor.DARK_GREEN, true),
DARK_AQUA('3', ChatColor.DARK_AQUA, true),
DARK_RED('4', ChatColor.DARK_RED, true),
DARK_PURPLE('5', ChatColor.DARK_PURPLE, true),
GOLD('6', ChatColor.GOLD, true),
GRAY('7', ChatColor.GRAY, true),
DARK_GRAY('8', ChatColor.DARK_GRAY, true),
BLUE('9', ChatColor.BLUE, true),
GREEN('a', ChatColor.GREEN, true),
AQUA('b', ChatColor.AQUA, true),
RED('c', ChatColor.RED, true),
LIGHT_PURPLE('d', ChatColor.LIGHT_PURPLE, true),
YELLOW('e', ChatColor.YELLOW, true),
WHITE('f', ChatColor.WHITE, true),
OBFUSCATED('k', ChatColor.MAGIC, false),
BOLD('l', ChatColor.BOLD, false),
STRIKETHROUGH('m', ChatColor.STRIKETHROUGH, false),
UNDERLINED('n', ChatColor.UNDERLINE, false),
ITALIC('o', ChatColor.ITALIC, false),
RESET('r', ChatColor.RESET, false);
private final char code;
private final ChatColor chatColor;
private final boolean isColor;
private static final Map<Character, ColorCode> BY_CHAR = new HashMap<>();
ColorCode(char code, ChatColor chatColor, boolean isColor) {
this.code = code;
this.chatColor = chatColor;
this.isColor = isColor;
}
static {
ColorCode[] var0 = values();
int l = var0.length;
for (int i = 0; i < l; ++i) {
ColorCode color = var0[i];
BY_CHAR.put(color.code, color);
}
}
public static ColorCode getByChar(char code) {
return BY_CHAR.get(code);
}
public char getCode() {
return code;
}
public ChatColor getChatColor() {
return chatColor;
}
public boolean isColor() {
return this.isColor;
}
}

View File

@ -0,0 +1,43 @@
package com.songoda.core.chat;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.core.utils.ColorUtils;
import java.awt.*;
public class ColorContainer {
private ColorCode colorCode;
private String hexCode;
public ColorContainer(ColorCode colorCode) {
this.colorCode = colorCode;
this.hexCode = null;
}
public ColorContainer(String hexCode) {
this.hexCode = hexCode;
if (ServerVersion.isServerVersionBelow(ServerVersion.V1_16)) {
this.colorCode = getColor();
this.hexCode = null;
}
}
public ColorCode getColorCode() {
return colorCode;
}
public String getHexCode() {
return hexCode;
}
public ColorCode getColor() {
if (colorCode != null) return colorCode;
if (hexCode == null) return null;
java.awt.Color jColor = new Color(
Integer.valueOf(hexCode.substring(0, 2), 16),
Integer.valueOf(hexCode.substring(2, 4), 16),
Integer.valueOf(hexCode.substring(4, 6), 16));
return ColorUtils.fromRGB(jColor.getRed(), jColor.getGreen(), jColor.getBlue());
}
}

View File

@ -1,12 +1,11 @@
package com.songoda.core.commands;
import com.songoda.core.input.ClickableChat;
import com.songoda.core.chat.ChatMessage;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@ -59,11 +58,9 @@ public class MainCommand extends AbstractCommand {
if (header != null) {
sender.sendMessage(header);
} else {
sender.sendMessage(String.format("%s%s %s» %sVersion %s Created with <3 by %sSongoda",
ChatColor.GOLD.toString() + ChatColor.BOLD, plugin.getDescription().getName(),
ChatColor.DARK_GRAY.toString(), ChatColor.GRAY.toString(), plugin.getDescription().getVersion(),
ChatColor.DARK_PURPLE.toString() + ChatColor.BOLD + ChatColor.ITALIC
));
new ChatMessage().fromText(String.format("#ff8080&l%s &8» &7Version %s Created with <3 by #ec4e74&l&oS#fa5b65&l&oo#ff6c55&l&on#ff7f44&l&og#ff9432&l&oo#ffaa1e&l&od#f4c009&l&oa",
plugin.getDescription().getName(), plugin.getDescription().getVersion()))
.sendTo(sender);
}
if (nestedCommands != null) {
@ -80,12 +77,12 @@ public class MainCommand extends AbstractCommand {
if (!isPlayer) {
sender.sendMessage(ChatColor.DARK_GRAY + "- " + ChatColor.YELLOW + cmd.getSyntax() + ChatColor.GRAY + " - " + cmd.getDescription());
} else if (cmd.getPermissionNode() == null || sender.hasPermission(cmd.getPermissionNode())) {
ClickableChat msg = new ClickableChat();
ChatMessage chatMessage = new ChatMessage();
final String c = "/" + command + " ";
msg.addMessage(ChatColor.DARK_GRAY + "- ")
chatMessage.addMessage(ChatColor.DARK_GRAY + "- ")
.addPromptCommand(ChatColor.YELLOW + c + cmd.getSyntax(), ChatColor.YELLOW + c + cmdStr, c + cmdStr)
.addMessage(ChatColor.GRAY + " - " + cmd.getDescription());
msg.sendTo((Player) sender);
chatMessage.sendTo((Player) sender);
}
}
}

View File

@ -920,16 +920,12 @@ public enum CompatibleSound {
ENTITY_ZOMBIE_BREAK_WOODEN_DOOR(ServerVersion.V1_13, v(ServerVersion.V1_9, "ENTITY_ZOMBIE_BREAK_DOOR_WOOD", true), v("ZOMBIE_WOODBREAK")),
ENTITY_ZOMBIE_CONVERTED_TO_DROWNED,
ENTITY_ZOMBIE_DEATH("ZOMBIE_DEATH"),
ENTITY_ZOMBIE_DESTROY_EGG,
ENTITY_ZOMBIE_DESTROY_EGG ,
ENTITY_ZOMBIE_HORSE_AMBIENT("HORSE_ZOMBIE_IDLE"),
ENTITY_ZOMBIE_HORSE_DEATH("HORSE_ZOMBIE_DEATH"),
ENTITY_ZOMBIE_HORSE_HURT("HORSE_ZOMBIE_HIT"),
ENTITY_ZOMBIE_HURT("ZOMBIE_HURT"),
ENTITY_ZOMBIE_INFECT("ZOMBIE_INFECT"),
ENTITY_ZOMBIE_PIGMAN_AMBIENT(ServerVersion.V1_13, v(ServerVersion.V1_9, "ENTITY_ZOMBIE_PIG_AMBIENT", true), v("ZOMBIE_PIG_IDLE")),
ENTITY_ZOMBIE_PIGMAN_ANGRY(ServerVersion.V1_13, v(ServerVersion.V1_9, "ENTITY_ZOMBIE_PIG_ANGRY", true), v("ZOMBIE_PIG_ANGRY")),
ENTITY_ZOMBIE_PIGMAN_DEATH(ServerVersion.V1_13, v(ServerVersion.V1_9, "ENTITY_ZOMBIE_PIG_DEATH", true), v("ZOMBIE_PIG_DEATH")),
ENTITY_ZOMBIE_PIGMAN_HURT(ServerVersion.V1_13, v(ServerVersion.V1_9, "ENTITY_ZOMBIE_PIG_HURT", true), v("ZOMBIE_PIG_HURT")),
ENTITY_ZOMBIE_STEP("ZOMBIE_WALK"),
ENTITY_ZOMBIE_VILLAGER_AMBIENT,
ENTITY_ZOMBIE_VILLAGER_CONVERTED("ZOMBIE_REMEDY"),

View File

@ -1,6 +1,7 @@
package com.songoda.core.gui;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.compatibility.CompatibleSound;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.core.gui.events.GuiClickEvent;
import com.songoda.core.gui.events.GuiCloseEvent;
@ -20,6 +21,7 @@ import java.util.Map;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.Hopper;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
@ -60,13 +62,14 @@ public class Gui {
protected Closable closer = null;
protected Droppable dropper = null;
protected Pagable pager = null;
protected CompatibleSound defaultSound = CompatibleSound.UI_BUTTON_CLICK;
public Gui() {
this.rows = 3;
}
public Gui(@NotNull GuiType type) {
this.inventoryType = type != null ? type : GuiType.STANDARD;
this.inventoryType = type;
switch (type) {
case HOPPER:
case DISPENSER:
@ -181,7 +184,7 @@ public class Gui {
@NotNull
public Gui setUnlocked(int row, int col) {
final int cell = col + row * 9;
final int cell = col + row * inventoryType.columns;
unlockedCells.put(cell, true);
return this;
}
@ -204,8 +207,8 @@ public class Gui {
@NotNull
public Gui setUnlockedRange(int cellRowFirst, int cellColFirst, int cellRowLast, int cellColLast) {
final int last = cellColLast + cellRowLast * 9;
for (int cell = cellColFirst + cellRowFirst * 9; cell <= last; ++cell) {
final int last = cellColLast + cellRowLast * inventoryType.columns;
for (int cell = cellColFirst + cellRowFirst * inventoryType.columns; cell <= last; ++cell) {
unlockedCells.put(cell, true);
}
return this;
@ -213,8 +216,8 @@ public class Gui {
@NotNull
public Gui setUnlockedRange(int cellRowFirst, int cellColFirst, int cellRowLast, int cellColLast, boolean open) {
final int last = cellColLast + cellRowLast * 9;
for (int cell = cellColFirst + cellRowFirst * 9; cell <= last; ++cell) {
final int last = cellColLast + cellRowLast * inventoryType.columns;
for (int cell = cellColFirst + cellRowFirst * inventoryType.columns; cell <= last; ++cell) {
unlockedCells.put(cell, open);
}
return this;
@ -228,7 +231,7 @@ public class Gui {
@NotNull
public Gui setUnlocked(int row, int col, boolean open) {
final int cell = col + row * 9;
final int cell = col + row * inventoryType.columns;
unlockedCells.put(cell, open);
return this;
}
@ -296,7 +299,7 @@ public class Gui {
@Nullable
public ItemStack getItem(int row, int col) {
final int cell = col + row * 9;
final int cell = col + row * inventoryType.columns;
if (inventory != null && unlockedCells.getOrDefault(cell, false)) {
return inventory.getItem(cell);
}
@ -314,7 +317,7 @@ public class Gui {
@NotNull
public Gui setItem(int row, int col, @Nullable ItemStack item) {
final int cell = col + row * 9;
final int cell = col + row * inventoryType.columns;
cellItems.put(cell, item);
if (inventory != null && cell >= 0 && cell < inventory.getSize()) {
inventory.setItem(cell, item);
@ -333,7 +336,7 @@ public class Gui {
@NotNull
public Gui highlightItem(int row, int col) {
final int cell = col + row * 9;
final int cell = col + row * inventoryType.columns;
ItemStack item = cellItems.get(cell);
if (item != null && item.getType() != Material.AIR) {
setItem(cell, ItemUtils.addGlow(item));
@ -352,7 +355,7 @@ public class Gui {
@NotNull
public Gui removeHighlight(int row, int col) {
final int cell = col + row * 9;
final int cell = col + row * inventoryType.columns;
ItemStack item = cellItems.get(cell);
if (item != null && item.getType() != Material.AIR) {
setItem(cell, ItemUtils.removeGlow(item));
@ -362,7 +365,7 @@ public class Gui {
@NotNull
public Gui updateItemLore(int row, int col, @NotNull String... lore) {
return updateItemLore(col + row * 9, lore);
return updateItemLore(col + row * inventoryType.columns, lore);
}
@NotNull
@ -376,7 +379,7 @@ public class Gui {
@NotNull
public Gui updateItemLore(int row, int col, @Nullable List<String> lore) {
return updateItemLore(col + row * 9, lore);
return updateItemLore(col + row * inventoryType.columns, lore);
}
@NotNull
@ -390,7 +393,7 @@ public class Gui {
@NotNull
public Gui updateItemName(int row, int col, @Nullable String name) {
return updateItemName(col + row * 9, name);
return updateItemName(col + row * inventoryType.columns, name);
}
@NotNull
@ -404,7 +407,7 @@ public class Gui {
@NotNull
public Gui updateItem(int row, int col, @Nullable String name, @NotNull String... lore) {
return updateItem(col + row * 9, name, lore);
return updateItem(col + row * inventoryType.columns, name, lore);
}
@NotNull
@ -418,7 +421,7 @@ public class Gui {
@NotNull
public Gui updateItem(int row, int col, @Nullable String name, @Nullable List<String> lore) {
return updateItem(col + row * 9, name, lore);
return updateItem(col + row * inventoryType.columns, name, lore);
}
@NotNull
@ -432,7 +435,7 @@ public class Gui {
@NotNull
public Gui updateItem(int row, int col, @NotNull ItemStack itemTo, @Nullable String title, @NotNull String... lore) {
return updateItem(col + row * 9, itemTo, title, lore);
return updateItem(col + row * inventoryType.columns, itemTo, title, lore);
}
@NotNull
@ -446,7 +449,7 @@ public class Gui {
@NotNull
public Gui updateItem(int row, int col, @NotNull CompatibleMaterial itemTo, @Nullable String title, @NotNull String... lore) {
return updateItem(col + row * 9, itemTo, title, lore);
return updateItem(col + row * inventoryType.columns, itemTo, title, lore);
}
@NotNull
@ -460,7 +463,7 @@ public class Gui {
@NotNull
public Gui updateItem(int row, int col, @NotNull ItemStack itemTo, @Nullable String title, @Nullable List<String> lore) {
return updateItem(col + row * 9, itemTo, title, lore);
return updateItem(col + row * inventoryType.columns, itemTo, title, lore);
}
@NotNull
@ -474,7 +477,7 @@ public class Gui {
@NotNull
public Gui updateItem(int row, int col, @NotNull CompatibleMaterial itemTo, @Nullable String title, @Nullable List<String> lore) {
return updateItem(col + row * 9, itemTo, title, lore);
return updateItem(col + row * inventoryType.columns, itemTo, title, lore);
}
@NotNull
@ -494,7 +497,7 @@ public class Gui {
@NotNull
public Gui setAction(int row, int col, @Nullable Clickable action) {
setConditional(col + row * 9, null, action);
setConditional(col + row * inventoryType.columns, null, action);
return this;
}
@ -506,7 +509,7 @@ public class Gui {
@NotNull
public Gui setAction(int row, int col, @Nullable ClickType type, @Nullable Clickable action) {
setConditional(col + row * 9, type, action);
setConditional(col + row * inventoryType.columns, type, action);
return this;
}
@ -520,8 +523,8 @@ public class Gui {
@NotNull
public Gui setActionForRange(int cellRowFirst, int cellColFirst, int cellRowLast, int cellColLast, @Nullable Clickable action) {
final int last = cellColLast + cellRowLast * 9;
for (int cell = cellColFirst + cellRowFirst * 9; cell <= last; ++cell) {
final int last = cellColLast + cellRowLast * inventoryType.columns;
for (int cell = cellColFirst + cellRowFirst * inventoryType.columns; cell <= last; ++cell) {
setConditional(cell, null, action);
}
return this;
@ -537,8 +540,8 @@ public class Gui {
@NotNull
public Gui setActionForRange(int cellRowFirst, int cellColFirst, int cellRowLast, int cellColLast, @Nullable ClickType type, @Nullable Clickable action) {
final int last = cellColLast + cellRowLast * 9;
for (int cell = cellColFirst + cellRowFirst * 9; cell <= last; ++cell) {
final int last = cellColLast + cellRowLast * inventoryType.columns;
for (int cell = cellColFirst + cellRowFirst * inventoryType.columns; cell <= last; ++cell) {
setConditional(cell, type, action);
}
return this;
@ -552,7 +555,7 @@ public class Gui {
@NotNull
public Gui clearActions(int row, int col) {
final int cell = col + row * 9;
final int cell = col + row * inventoryType.columns;
conditionalButtons.remove(cell);
return this;
}
@ -566,7 +569,7 @@ public class Gui {
@NotNull
public Gui setButton(int row, int col, @Nullable ItemStack item, @Nullable Clickable action) {
final int cell = col + row * 9;
final int cell = col + row * inventoryType.columns;
setItem(cell, item);
setConditional(cell, null, action);
return this;
@ -581,7 +584,7 @@ public class Gui {
@NotNull
public Gui setButton(int row, int col, @Nullable ItemStack item, @Nullable ClickType type, @Nullable Clickable action) {
final int cell = col + row * 9;
final int cell = col + row * inventoryType.columns;
setItem(cell, item);
setConditional(cell, type, action);
return this;
@ -641,7 +644,7 @@ public class Gui {
@NotNull
public Gui setNextPage(int row, int col, @NotNull ItemStack item) {
nextPageIndex = col + row * 9;
nextPageIndex = col + row * inventoryType.columns;
nextPage = item;
if (page < pages) {
setButton(nextPageIndex, nextPage, ClickType.LEFT, (event) -> this.nextPage());
@ -661,7 +664,7 @@ public class Gui {
@NotNull
public Gui setPrevPage(int row, int col, @NotNull ItemStack item) {
prevPageIndex = col + row * 9;
prevPageIndex = col + row * inventoryType.columns;
prevPage = item;
if (page > 1) {
setButton(prevPageIndex, prevPage, ClickType.LEFT, (event) -> this.prevPage());
@ -758,7 +761,7 @@ public class Gui {
@NotNull
protected Inventory generateInventory(@NotNull GuiManager manager) {
this.guiManager = manager;
final int cells = rows * 9;
final int cells = rows * inventoryType.columns;
createInventory();
for (int i = 0; i < cells; ++i) {
@ -771,14 +774,15 @@ public class Gui {
protected void createInventory() {
final InventoryType t = inventoryType == null ? InventoryType.CHEST : inventoryType.type;
switch (t) {
case DISPENSER:
case HOPPER:
inventory = Bukkit.getServer().createInventory(new GuiHolder(guiManager, this), t,
inventory = new GuiHolder(guiManager, this).newInventory(t,
title == null ? "" : trimTitle(title));
break;
default:
inventory = Bukkit.getServer().createInventory(new GuiHolder(guiManager, this), rows * 9,
inventory = new GuiHolder(guiManager, this).newInventory(rows * 9,
title == null ? "" : trimTitle(title));
}
}
@ -792,7 +796,7 @@ public class Gui {
if (inventory == null) {
return;
}
final int cells = rows * 9;
final int cells = rows * inventoryType.columns;
for (int i = 0; i < cells; ++i) {
final ItemStack item = cellItems.get(i);
inventory.setItem(i, item != null ? item : (unlockedCells.getOrDefault(i, false) ? AIR : blankItem));
@ -858,4 +862,11 @@ public class Gui {
}
}
public CompatibleSound getDefaultSound() {
return defaultSound;
}
public void setDefaultSound(CompatibleSound sound) {
defaultSound = sound;
}
}

View File

@ -1,5 +1,7 @@
package com.songoda.core.gui;
import org.bukkit.Bukkit;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
@ -27,4 +29,12 @@ class GuiHolder implements InventoryHolder {
public Gui getGUI() {
return gui;
}
public Inventory newInventory(int size, String title) {
return Bukkit.createInventory(this, size, title);
}
public Inventory newInventory(InventoryType type, String title) {
return Bukkit.createInventory(this, type, title);
}
}

View File

@ -187,6 +187,7 @@ public class GuiManager {
Inventory openInv = event.getInventory();
final Player player = (Player) event.getWhoClicked();
Gui gui;
if (openInv.getHolder() != null && openInv.getHolder() instanceof GuiHolder
&& ((GuiHolder) openInv.getHolder()).manager.uuid.equals(manager.uuid)) {
@ -216,15 +217,15 @@ public class GuiManager {
} // did we click the gui or in the user's inventory?
else if (event.getRawSlot() < gui.inventory.getSize()) {// or could use event.getClickedInventory() == gui.inventory
// allow event if this is not a GUI element
event.setCancelled(!gui.unlockedCells.entrySet().stream().anyMatch(e -> event.getSlot() == e.getKey() && e.getValue()));
event.setCancelled(gui.unlockedCells.entrySet().stream().noneMatch(e -> event.getSlot() == e.getKey() && e.getValue()));
// process button press
if (gui.onClick(manager, player, openInv, event)) {
player.playSound(player.getLocation(), CompatibleSound.UI_BUTTON_CLICK.getSound(), 1F, 1F);
player.playSound(player.getLocation(), gui.getDefaultSound().getSound(), 1F, 1F);
}
} else {
// Player clicked in the bottom inventory while GUI is open
if (gui.onClickPlayerInventory(manager, player, openInv, event)) {
player.playSound(player.getLocation(), CompatibleSound.UI_BUTTON_CLICK.getSound(), 1F, 1F);
player.playSound(player.getLocation(), gui.getDefaultSound().getSound(), 1F, 1F);
} else if (!gui.acceptsItems || event.getAction() == InventoryAction.MOVE_TO_OTHER_INVENTORY) {
event.setCancelled(true);
if(gui instanceof AnvilGui) {

View File

@ -4,14 +4,18 @@ import org.bukkit.event.inventory.InventoryType;
public enum GuiType {
STANDARD(InventoryType.CHEST),
DISPENSER(InventoryType.DISPENSER),
HOPPER(InventoryType.HOPPER);
STANDARD(InventoryType.CHEST, 6, 9),
DISPENSER(InventoryType.DISPENSER, 9, 3),
HOPPER(InventoryType.HOPPER, 5, 1);
protected final InventoryType type;
protected final int rows;
protected final int columns;
private GuiType(InventoryType type) {
private GuiType(InventoryType type, int rows, int columns) {
this.type = type;
this.rows = rows;
this.columns = columns;
}
}
}

View File

@ -1,147 +0,0 @@
package com.songoda.core.input;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.songoda.core.compatibility.ServerVersion;
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.logging.Level;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
/**
* Send chat packets with embedded links
*
* @since 2019-09-01
* @author jascotty2
*/
public class ClickableChat {
private static final Gson gson = new GsonBuilder().create();
List<JsonObject> textList = new ArrayList();
public void clear() {
textList.clear();
}
public ClickableChat addMessage(String s) {
JsonObject txt = new JsonObject();
txt.addProperty("text", s);
textList.add(txt);
return this;
}
public ClickableChat addRunCommand(String text, String hoverText, String cmd) {
JsonObject txt = new JsonObject();
txt.addProperty("text", text);
JsonObject hover = new JsonObject();
hover.addProperty("action", "show_text");
hover.addProperty("value", hoverText);
txt.add("hoverEvent", hover);
JsonObject click = new JsonObject();
click.addProperty("action", "run_command");
click.addProperty("value", cmd);
txt.add("clickEvent", click);
textList.add(txt);
return this;
}
public ClickableChat addPromptCommand(String text, String hoverText, String cmd) {
JsonObject txt = new JsonObject();
txt.addProperty("text", text);
JsonObject hover = new JsonObject();
hover.addProperty("action", "show_text");
hover.addProperty("value", hoverText);
txt.add("hoverEvent", hover);
JsonObject click = new JsonObject();
click.addProperty("action", "suggest_command");
click.addProperty("value", cmd);
txt.add("clickEvent", click);
textList.add(txt);
return this;
}
public ClickableChat addURL(String text, String hoverText, String url) {
JsonObject txt = new JsonObject();
txt.addProperty("text", text);
JsonObject hover = new JsonObject();
hover.addProperty("action", "show_text");
hover.addProperty("value", hoverText);
txt.add("hoverEvent", hover);
JsonObject click = new JsonObject();
click.addProperty("action", "open_url");
click.addProperty("value", url);
txt.add("clickEvent", hover);
textList.add(txt);
return this;
}
@Override
public String toString() {
return gson.toJson(textList);
}
public void sendTo(Player p) {
if (enabled) {
try {
Object packet = mc_PacketPlayOutChat_new.newInstance(mc_IChatBaseComponent_ChatSerializer_a.invoke(null, this.toString()));
Object cbPlayer = cb_craftPlayer_getHandle.invoke(p);
Object mcConnection = mc_entityPlayer_playerConnection.get(cbPlayer);
mc_playerConnection_sendPacket.invoke(mcConnection, packet);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
Bukkit.getLogger().log(Level.WARNING, "Problem preparing raw chat packets (disabling further packets)", ex);
enabled = false;
}
}
}
private static boolean enabled = ServerVersion.isServerVersionAtLeast(ServerVersion.V1_8);
private static Method mc_IChatBaseComponent_ChatSerializer_a;
private static Constructor mc_PacketPlayOutChat_new;
private static Method cb_craftPlayer_getHandle;
private static Field mc_entityPlayer_playerConnection;
private static Method mc_playerConnection_sendPacket;
static {
init();
}
static void init() {
if (enabled) {
try {
final String version = ServerVersion.getServerVersionString();
Class cb_craftPlayerClazz;
Class mc_entityPlayerClazz;
Class mc_playerConnectionClazz;
Class mc_PacketInterface;
Class mc_IChatBaseComponent;
Class mc_IChatBaseComponent_ChatSerializer;
Class mc_PacketPlayOutChat;
cb_craftPlayerClazz = Class.forName("org.bukkit.craftbukkit." + version + ".entity.CraftPlayer");
cb_craftPlayer_getHandle = cb_craftPlayerClazz.getDeclaredMethod("getHandle");
mc_entityPlayerClazz = Class.forName("net.minecraft.server." + version + ".EntityPlayer");
mc_entityPlayer_playerConnection = mc_entityPlayerClazz.getDeclaredField("playerConnection");
mc_playerConnectionClazz = Class.forName("net.minecraft.server." + version + ".PlayerConnection");
mc_PacketInterface = Class.forName("net.minecraft.server." + version + ".Packet");
mc_playerConnection_sendPacket = mc_playerConnectionClazz.getDeclaredMethod("sendPacket", mc_PacketInterface);
mc_IChatBaseComponent = Class.forName("net.minecraft.server." + version + ".IChatBaseComponent");
mc_IChatBaseComponent_ChatSerializer = Class.forName("net.minecraft.server." + version + ".IChatBaseComponent$ChatSerializer");
mc_IChatBaseComponent_ChatSerializer_a = mc_IChatBaseComponent_ChatSerializer.getMethod("a", String.class);
mc_PacketPlayOutChat = Class.forName("net.minecraft.server." + version + ".PacketPlayOutChat");
mc_PacketPlayOutChat_new = mc_PacketPlayOutChat.getConstructor(mc_IChatBaseComponent);
} catch (Throwable ex) {
Bukkit.getLogger().log(Level.WARNING, "Problem preparing raw chat packets (disabling further packets)", ex);
enabled = false;
}
}
}
}

View File

@ -1,9 +1,12 @@
package com.songoda.core.locale;
import com.songoda.core.chat.ChatMessage;
import com.songoda.core.compatibility.ServerVersion;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import com.songoda.core.utils.TextUtils;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@ -25,8 +28,8 @@ public class Message {
} catch (Exception ex) {
}
}
private String prefix = null;
private String message;
private ChatMessage prefix = null;
private ChatMessage message;
/**
* create a new message
@ -34,6 +37,17 @@ public class Message {
* @param message the message text
*/
public Message(String message) {
ChatMessage chatMessage = new ChatMessage();
chatMessage.fromText(message);
this.message = chatMessage;
}
/**
* create a new message
*
* @param message the message text
*/
public Message(ChatMessage message) {
this.message = message;
}
@ -46,27 +60,17 @@ public class Message {
player.sendMessage(this.getMessage());
}
/**
* Format and send the held message with the
* appended plugin prefix to a player
*
* @param player player to send the message to
*/
public void sendPrefixedMessage(Player player) {
player.sendMessage(this.getPrefixedMessage());
}
/**
* Format and send the held message to a player
*
* @param sender command sender to send the message to
*/
public void sendMessage(CommandSender sender) {
sender.sendMessage(this.getMessage());
message.sendTo(sender);
}
/**
* Format and send the held message to a player as a title message
* Format and send the held message to a player as a title messagexc
*
* @param sender command sender to send the message to
*/
@ -105,7 +109,7 @@ public class Message {
* @param sender command sender to send the message to
*/
public void sendPrefixedMessage(CommandSender sender) {
sender.sendMessage(this.getPrefixedMessage());
this.message.sendTo(this.prefix, sender);
}
/**
@ -115,8 +119,7 @@ public class Message {
* @return the prefixed message
*/
public String getPrefixedMessage() {
return ChatColor.translateAlternateColorCodes('&',(prefix == null ? "" : this.prefix)
+ " " + this.message);
return TextUtils.formatText((prefix == null ? "" : this.prefix) + " " + this.message.toText());
}
/**
@ -125,7 +128,7 @@ public class Message {
* @return the message
*/
public String getMessage() {
return ChatColor.translateAlternateColorCodes('&', this.message);
return TextUtils.formatText(this.message.toText());
}
/**
@ -134,7 +137,7 @@ public class Message {
* @return the message
*/
public List<String> getMessageLines() {
return Arrays.asList(ChatColor.translateAlternateColorCodes('&', this.message).split("\n|\\|"));
return Arrays.asList(ChatColor.translateAlternateColorCodes('&', this.message.toText()).split("\n|\\|"));
}
/**
@ -143,7 +146,7 @@ public class Message {
* @return the message
*/
public String getUnformattedMessage() {
return this.message;
return this.message.toText();
}
/**
@ -161,12 +164,17 @@ public class Message {
}
Message setPrefix(String prefix) {
this.prefix = prefix;
this.prefix = new ChatMessage();
this.prefix.fromText(prefix + " ");
return this;
}
@Override
public String toString() {
return this.message;
return this.message.toString();
}
public String toText() {
return this.message.toText();
}
}

View File

@ -0,0 +1,69 @@
package com.songoda.core.utils;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import com.songoda.core.chat.ColorCode;
import org.bukkit.ChatColor;
public class ColorUtils {
private static Map<ColorCode, ColorSet<Integer, Integer, Integer>> colorMap = new HashMap<>();
static {
colorMap.put(ColorCode.BLACK, new ColorSet<>(0, 0, 0));
colorMap.put(ColorCode.DARK_BLUE, new ColorSet<>(0, 0, 170));
colorMap.put(ColorCode.DARK_GREEN, new ColorSet<>(0, 170, 0));
colorMap.put(ColorCode.DARK_AQUA, new ColorSet<>(0, 170, 170));
colorMap.put(ColorCode.DARK_RED, new ColorSet<>(170, 0, 0));
colorMap.put(ColorCode.DARK_PURPLE, new ColorSet<>(170, 0, 170));
colorMap.put(ColorCode.GOLD, new ColorSet<>(255, 170, 0));
colorMap.put(ColorCode.GRAY, new ColorSet<>(170, 170, 170));
colorMap.put(ColorCode.DARK_GRAY, new ColorSet<>(85, 85, 85));
colorMap.put(ColorCode.BLUE, new ColorSet<>(85, 85, 255));
colorMap.put(ColorCode.GREEN, new ColorSet<>(85, 255, 85));
colorMap.put(ColorCode.AQUA, new ColorSet<>(85, 255, 255));
colorMap.put(ColorCode.RED, new ColorSet<>(255, 85, 85));
colorMap.put(ColorCode.LIGHT_PURPLE, new ColorSet<>(255, 85, 255));
colorMap.put(ColorCode.YELLOW, new ColorSet<>(255, 255, 85));
colorMap.put(ColorCode.WHITE, new ColorSet<>(255, 255, 255));
}
private static class ColorSet<R, G, B> {
R red = null;
G green = null;
B blue = null;
ColorSet(R red, G green, B blue) {
this.red = red;
this.green = green;
this.blue = blue;
}
public R getRed() {
return red;
}
public G getGreen() {
return green;
}
public B getBlue() {
return blue;
}
}
public static ColorCode fromRGB(int r, int g, int b) {
TreeMap<Integer, ColorCode> closest = new TreeMap<>();
colorMap.forEach((color, set) -> {
int red = Math.abs(r - set.getRed());
int green = Math.abs(g - set.getGreen());
int blue = Math.abs(b - set.getBlue());
closest.put(red + green + blue, color);
});
return closest.firstEntry().getValue();
}
}

View File

@ -414,7 +414,7 @@ public class ItemUtils {
if (hand == CompatibleHand.MAIN_HAND)
player.setItemInHand(result > 0 ? item : null);
else
player.getEquipment().setItemInOffHand(result > 0 ? item : null);
player.getInventory().setItemInOffHand(result > 0 ? item : null);
}
/**

View File

@ -66,5 +66,11 @@
<version>1.16.1-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.minecraft</groupId>
<artifactId>server</artifactId>
<version>1.16.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>