Support 1.17

This commit is contained in:
Brianna 2021-06-13 17:42:02 -05:00
parent 24ee590f6b
commit 8d1adcbd79
7 changed files with 17 additions and 468 deletions

12
pom.xml
View File

@ -41,7 +41,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<version>3.3.0-SNAPSHOT</version>
<executions>
<execution>
<id>shaded</id>
@ -85,19 +85,23 @@
</resource>
</resources>
</build>
<pluginRepositories>
<pluginRepository>
<id>apache.snapshots</id>
<url>https://repository.apache.org/snapshots/</url>
</pluginRepository>
</pluginRepositories>
<repositories>
<repository>
<id>public</id>
<url>https://repo.songoda.com/repository/public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.16.4</version>
<version>1.17</version>
<scope>provided</scope>
</dependency>
<dependency>

View File

@ -8,7 +8,6 @@ import com.songoda.core.configuration.Config;
import com.songoda.core.gui.GuiManager;
import com.songoda.epicvouchers.commands.*;
import com.songoda.epicvouchers.handlers.Connections;
import com.songoda.epicvouchers.libraries.BountifulAPI;
import com.songoda.epicvouchers.libraries.inventory.FastInv;
import com.songoda.epicvouchers.libraries.inventory.IconInv;
import com.songoda.epicvouchers.listeners.PlayerCommandListener;
@ -79,7 +78,6 @@ public class EpicVouchers extends SongodaPlugin {
FastInv.init(this);
IconInv.init(this);
BountifulAPI.init(this);
this.connections = new Connections(this);
this.coolDowns = new CoolDownManager(this);

View File

@ -1,306 +0,0 @@
package com.songoda.epicvouchers.libraries;
import com.songoda.epicvouchers.EpicVouchers;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class BountifulAPI {
public static String nmsver;
private static boolean useOldMethods = false;
private static EpicVouchers instance;
@Deprecated
public static void sendTitle(Player player, Integer fadeIn, Integer stay, Integer fadeOut, String message) {
sendTitle(player, fadeIn, stay, fadeOut, message, null);
}
@Deprecated
public static void sendSubtitle(Player player, Integer fadeIn, Integer stay, Integer fadeOut, String message) {
sendTitle(player, fadeIn, stay, fadeOut, null, message);
}
@Deprecated
public static void sendFullTitle(Player player, Integer fadeIn, Integer stay, Integer fadeOut, String title, String subtitle) {
sendTitle(player, fadeIn, stay, fadeOut, title, subtitle);
}
@Deprecated
public static Integer getPlayerProtocol(Player player) {
/* Returns the 1.8 protocol version as this is the only protocol a player can possibly be on with Spigot 1.8 */
return 47;
}
public static void sendPacket(Player player, Object packet) {
try {
Object handle = player.getClass().getMethod("getHandle").invoke(player);
Object playerConnection = handle.getClass().getField("playerConnection").get(handle);
playerConnection.getClass().getMethod("sendPacket", getNMSClass("Packet")).invoke(playerConnection, packet);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Class<?> getNMSClass(String name) {
String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
try {
return Class.forName("net.minecraft.server." + version + "." + name);
} catch (ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
public static void sendTitle(Player player, Integer fadeIn, Integer stay, Integer fadeOut, String title, String subtitle) {
try {
Object e;
Object chatTitle;
Object chatSubtitle;
Constructor subtitleConstructor;
Object titlePacket;
Object subtitlePacket;
if (title != null) {
title = ChatColor.translateAlternateColorCodes('&', title);
title = title.replaceAll("%player%", player.getDisplayName());
// Times packets
e = getNMSClass("PacketPlayOutTitle").getDeclaredClasses()[0].getField("TIMES").get((Object) null);
chatTitle = getNMSClass("IChatBaseComponent").getDeclaredClasses()[0].getMethod("a", new Class[]{String.class}).invoke((Object) null, new Object[]{"{\"text\":\"" + title + "\"}"});
subtitleConstructor = getNMSClass("PacketPlayOutTitle").getConstructor(new Class[]{getNMSClass("PacketPlayOutTitle").getDeclaredClasses()[0], getNMSClass("IChatBaseComponent"), Integer.TYPE, Integer.TYPE, Integer.TYPE});
titlePacket = subtitleConstructor.newInstance(new Object[]{e, chatTitle, fadeIn, stay, fadeOut});
sendPacket(player, titlePacket);
e = getNMSClass("PacketPlayOutTitle").getDeclaredClasses()[0].getField("TITLE").get((Object) null);
chatTitle = getNMSClass("IChatBaseComponent").getDeclaredClasses()[0].getMethod("a", new Class[]{String.class}).invoke((Object) null, new Object[]{"{\"text\":\"" + title + "\"}"});
subtitleConstructor = getNMSClass("PacketPlayOutTitle").getConstructor(new Class[]{getNMSClass("PacketPlayOutTitle").getDeclaredClasses()[0], getNMSClass("IChatBaseComponent")});
titlePacket = subtitleConstructor.newInstance(new Object[]{e, chatTitle});
sendPacket(player, titlePacket);
}
if (subtitle != null) {
subtitle = ChatColor.translateAlternateColorCodes('&', subtitle);
subtitle = subtitle.replaceAll("%player%", player.getDisplayName());
// Times packets
e = getNMSClass("PacketPlayOutTitle").getDeclaredClasses()[0].getField("TIMES").get((Object) null);
chatSubtitle = getNMSClass("IChatBaseComponent").getDeclaredClasses()[0].getMethod("a", new Class[]{String.class}).invoke((Object) null, new Object[]{"{\"text\":\"" + title + "\"}"});
subtitleConstructor = getNMSClass("PacketPlayOutTitle").getConstructor(new Class[]{getNMSClass("PacketPlayOutTitle").getDeclaredClasses()[0], getNMSClass("IChatBaseComponent"), Integer.TYPE, Integer.TYPE, Integer.TYPE});
subtitlePacket = subtitleConstructor.newInstance(new Object[]{e, chatSubtitle, fadeIn, stay, fadeOut});
sendPacket(player, subtitlePacket);
e = getNMSClass("PacketPlayOutTitle").getDeclaredClasses()[0].getField("SUBTITLE").get((Object) null);
chatSubtitle = getNMSClass("IChatBaseComponent").getDeclaredClasses()[0].getMethod("a", new Class[]{String.class}).invoke((Object) null, new Object[]{"{\"text\":\"" + subtitle + "\"}"});
subtitleConstructor = getNMSClass("PacketPlayOutTitle").getConstructor(new Class[]{getNMSClass("PacketPlayOutTitle").getDeclaredClasses()[0], getNMSClass("IChatBaseComponent"), Integer.TYPE, Integer.TYPE, Integer.TYPE});
subtitlePacket = subtitleConstructor.newInstance(new Object[]{e, chatSubtitle, fadeIn, stay, fadeOut});
sendPacket(player, subtitlePacket);
}
} catch (Exception var11) {
var11.printStackTrace();
}
}
public static void clearTitle(Player player) {
sendTitle(player, 0, 0, 0, "", "");
}
public static void sendTabTitle(Player player, String header, String footer) {
if (header == null) header = "";
header = ChatColor.translateAlternateColorCodes('&', header);
if (footer == null) footer = "";
footer = ChatColor.translateAlternateColorCodes('&', footer);
header = header.replaceAll("%player%", player.getDisplayName());
footer = footer.replaceAll("%player%", player.getDisplayName());
try {
Object tabHeader = getNMSClass("IChatBaseComponent").getDeclaredClasses()[0].getMethod("a", String.class).invoke(null, "{\"text\":\"" + header + "\"}");
Object tabFooter = getNMSClass("IChatBaseComponent").getDeclaredClasses()[0].getMethod("a", String.class).invoke(null, "{\"text\":\"" + footer + "\"}");
Constructor<?> titleConstructor = getNMSClass("PacketPlayOutPlayerListHeaderFooter").getConstructor();
Object packet = titleConstructor.newInstance();
try {
Field aField = packet.getClass().getDeclaredField("a");
aField.setAccessible(true);
aField.set(packet, tabHeader);
Field bField = packet.getClass().getDeclaredField("b");
bField.setAccessible(true);
bField.set(packet, tabFooter);
} catch (Exception e) {
Field aField = packet.getClass().getDeclaredField("header");
aField.setAccessible(true);
aField.set(packet, tabHeader);
Field bField = packet.getClass().getDeclaredField("footer");
bField.setAccessible(true);
bField.set(packet, tabFooter);
}
sendPacket(player, packet);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void sendActionBar(Player player, String message) {
if (!player.isOnline()) {
return; // Player may have logged out
}
try {
Class<?> craftPlayerClass = Class.forName("org.bukkit.craftbukkit." + nmsver + ".entity.CraftPlayer");
Object craftPlayer = craftPlayerClass.cast(player);
Object packet;
Class<?> packetPlayOutChatClass = Class.forName("net.minecraft.server." + nmsver + ".PacketPlayOutChat");
Class<?> packetClass = Class.forName("net.minecraft.server." + nmsver + ".Packet");
if (useOldMethods) {
Class<?> chatSerializerClass = Class.forName("net.minecraft.server." + nmsver + ".ChatSerializer");
Class<?> iChatBaseComponentClass = Class.forName("net.minecraft.server." + nmsver + ".IChatBaseComponent");
Method m3 = chatSerializerClass.getDeclaredMethod("a", String.class);
Object cbc = iChatBaseComponentClass.cast(m3.invoke(chatSerializerClass, "{\"text\": \"" + message + "\"}"));
packet = packetPlayOutChatClass.getConstructor(new Class<?>[]{iChatBaseComponentClass, byte.class}).newInstance(cbc, (byte) 2);
} else {
Class<?> chatComponentTextClass = Class.forName("net.minecraft.server." + nmsver + ".ChatComponentText");
Class<?> iChatBaseComponentClass = Class.forName("net.minecraft.server." + nmsver + ".IChatBaseComponent");
try {
Class<?> chatMessageTypeClass = Class.forName("net.minecraft.server." + nmsver + ".ChatMessageType");
Object[] chatMessageTypes = chatMessageTypeClass.getEnumConstants();
Object chatMessageType = null;
for (Object obj : chatMessageTypes) {
if (obj.toString().equals("GAME_INFO")) {
chatMessageType = obj;
}
}
Object chatCompontentText = chatComponentTextClass.getConstructor(new Class<?>[]{String.class}).newInstance(message);
packet = packetPlayOutChatClass.getConstructor(new Class<?>[]{iChatBaseComponentClass, chatMessageTypeClass}).newInstance(chatCompontentText, chatMessageType);
} catch (ClassNotFoundException cnfe) {
Object chatCompontentText = chatComponentTextClass.getConstructor(new Class<?>[]{String.class}).newInstance(message);
packet = packetPlayOutChatClass.getConstructor(new Class<?>[]{iChatBaseComponentClass, byte.class}).newInstance(chatCompontentText, (byte) 2);
}
}
Method craftPlayerHandleMethod = craftPlayerClass.getDeclaredMethod("getHandle");
Object craftPlayerHandle = craftPlayerHandleMethod.invoke(craftPlayer);
Field playerConnectionField = craftPlayerHandle.getClass().getDeclaredField("playerConnection");
Object playerConnection = playerConnectionField.get(craftPlayerHandle);
Method sendPacketMethod = playerConnection.getClass().getDeclaredMethod("sendPacket", packetClass);
sendPacketMethod.invoke(playerConnection, packet);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void sendActionBarPost112(Player player, String message) {
if (!player.isOnline()) {
return; // Player may have logged out
}
try {
Class<?> craftPlayerClass = Class.forName("org.bukkit.craftbukkit." + nmsver + ".entity.CraftPlayer");
Object craftPlayer = craftPlayerClass.cast(player);
Object ppoc;
Class<?> c4 = Class.forName("net.minecraft.server." + nmsver + ".PacketPlayOutChat");
Class<?> c5 = Class.forName("net.minecraft.server." + nmsver + ".Packet");
Class<?> c2 = Class.forName("net.minecraft.server." + nmsver + ".ChatComponentText");
Class<?> c3 = Class.forName("net.minecraft.server." + nmsver + ".IChatBaseComponent");
Class<?> chatMessageTypeClass = Class.forName("net.minecraft.server." + nmsver + ".ChatMessageType");
Object[] chatMessageTypes = chatMessageTypeClass.getEnumConstants();
Object chatMessageType = null;
for (Object obj : chatMessageTypes) {
if (obj.toString().equals("GAME_INFO")) {
chatMessageType = obj;
}
}
Object o = c2.getConstructor(new Class<?>[]{String.class}).newInstance(message);
ppoc = c4.getConstructor(new Class<?>[]{c3, chatMessageTypeClass}).newInstance(o, chatMessageType);
Method m1 = craftPlayerClass.getDeclaredMethod("getHandle");
Object h = m1.invoke(craftPlayer);
Field f1 = h.getClass().getDeclaredField("playerConnection");
Object pc = f1.get(h);
Method m5 = pc.getClass().getDeclaredMethod("sendPacket", c5);
m5.invoke(pc, ppoc);
} catch (Exception ex) {
ex.printStackTrace();
}
}
private static void sendActionBarPre112(Player player, String message) {
if (!player.isOnline()) {
return; // Player may have logged out
}
try {
Class<?> craftPlayerClass = Class.forName("org.bukkit.craftbukkit." + nmsver + ".entity.CraftPlayer");
Object craftPlayer = craftPlayerClass.cast(player);
Object ppoc;
Class<?> c4 = Class.forName("net.minecraft.server." + nmsver + ".PacketPlayOutChat");
Class<?> c5 = Class.forName("net.minecraft.server." + nmsver + ".Packet");
if (useOldMethods) {
Class<?> c2 = Class.forName("net.minecraft.server." + nmsver + ".ChatSerializer");
Class<?> c3 = Class.forName("net.minecraft.server." + nmsver + ".IChatBaseComponent");
Method m3 = c2.getDeclaredMethod("a", String.class);
Object cbc = c3.cast(m3.invoke(c2, "{\"text\": \"" + message + "\"}"));
ppoc = c4.getConstructor(new Class<?>[]{c3, byte.class}).newInstance(cbc, (byte) 2);
} else {
Class<?> c2 = Class.forName("net.minecraft.server." + nmsver + ".ChatComponentText");
Class<?> c3 = Class.forName("net.minecraft.server." + nmsver + ".IChatBaseComponent");
Object o = c2.getConstructor(new Class<?>[]{String.class}).newInstance(message);
ppoc = c4.getConstructor(new Class<?>[]{c3, byte.class}).newInstance(o, (byte) 2);
}
Method m1 = craftPlayerClass.getDeclaredMethod("getHandle");
Object h = m1.invoke(craftPlayer);
Field f1 = h.getClass().getDeclaredField("playerConnection");
Object pc = f1.get(h);
Method m5 = pc.getClass().getDeclaredMethod("sendPacket", c5);
m5.invoke(pc, ppoc);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void sendActionBar(final Player player, final String message, int duration) {
sendActionBar(player, message);
if (duration >= 0) {
// Sends empty message at the end of the duration. Allows messages shorter than 3 seconds, ensures precision.
new BukkitRunnable() {
@Override
public void run() {
sendActionBar(player, "");
}
}.runTaskLater(instance, duration + 1);
}
// Re-sends the messages every 3 seconds so it doesn't go away from the player's screen.
while (duration > 60) {
duration -= 60;
int sched = duration % 60;
new BukkitRunnable() {
@Override
public void run() {
sendActionBar(player, message);
}
}.runTaskLater(instance, (long) sched);
}
}
public static void sendActionBarToAllPlayers(String message) {
sendActionBarToAllPlayers(message, -1);
}
public static void sendActionBarToAllPlayers(String message, int duration) {
for (Player p : Bukkit.getOnlinePlayers()) {
sendActionBar(p, message, duration);
}
}
public static void init(EpicVouchers epicVouchers) {
instance = epicVouchers;
nmsver = Bukkit.getServer().getClass().getPackage().getName();
nmsver = nmsver.substring(nmsver.lastIndexOf(".") + 1);
if (nmsver.equalsIgnoreCase("v1_8_R1") || nmsver.equalsIgnoreCase("v1_7_")) { // Not sure if 1_7 works for the protocol hack?
useOldMethods = true;
}
}
}

View File

@ -1,102 +0,0 @@
package com.songoda.epicvouchers.utils;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.lang.reflect.Field;
public class NMSUtil {
public static String getVersion() {
String name = Bukkit.getServer().getClass().getPackage().getName();
return name.substring(name.lastIndexOf('.') + 1) + ".";
}
public static int getVersionNumber() {
String name = getVersion().substring(3);
return Integer.valueOf(name.substring(0, name.length() - 4));
}
public static int getVersionReleaseNumber() {
String NMSVersion = getVersion();
return Integer.valueOf(NMSVersion.substring(NMSVersion.length() - 2).replace(".", ""));
}
public static Class<?> getNMSClass(String className) {
try {
String fullName = "net.minecraft.server." + getVersion() + className;
Class<?> clazz = Class.forName(fullName);
return clazz;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static Class<?> getCraftClass(String className) throws ClassNotFoundException {
try {
String fullName = "org.bukkit.craftbukkit." + getVersion() + className;
Class<?> clazz = Class.forName(fullName);
return clazz;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static Field getField(Class<?> clazz, String name, boolean declared) {
try {
Field field;
if (declared) {
field = clazz.getDeclaredField(name);
} else {
field = clazz.getField(name);
}
field.setAccessible(true);
return field;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static Object getFieldObject(Object object, Field field) {
try {
return field.get(object);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void setField(Object object, String fieldName, Object fieldValue, boolean declared) {
try {
Field field;
if (declared) {
field = object.getClass().getDeclaredField(fieldName);
} else {
field = object.getClass().getField(fieldName);
}
field.setAccessible(true);
field.set(object, fieldValue);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void sendPacket(Player player, Object packet) {
try {
Object handle = player.getClass().getMethod("getHandle").invoke(player);
Object playerConnection = handle.getClass().getField("playerConnection").get(handle);
playerConnection.getClass().getMethod("sendPacket", getNMSClass("Packet")).invoke(playerConnection, packet);
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -1,48 +0,0 @@
package com.songoda.epicvouchers.utils;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import com.songoda.core.compatibility.ServerVersion;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.UUID;
public class SkullUtils {
/*
* Custom skull texture. Should probably be moved to SongodaCore.
*/
public static ItemStack customTexture(ItemStack itemStack, String texture) {
if (ServerVersion.isServerVersionBelow(ServerVersion.V1_8)) {
return itemStack;
}
if (texture == null || texture.isEmpty()) {
return itemStack;
}
SkullMeta skullMeta = (SkullMeta)itemStack.getItemMeta();
GameProfile gameProfile = new GameProfile(UUID.nameUUIDFromBytes(texture.getBytes()), "CustomHead");
if (texture.endsWith("=")) {
gameProfile.getProperties().put("textures", new Property("texture", texture.replaceAll("=", "")));
} else {
byte[] encodedData = Base64.getEncoder().encode(String.format("{textures:{SKIN:{url:\"http://textures.minecraft.net/texture/%s\"}}}", texture).getBytes());
gameProfile.getProperties().put("textures", new Property("textures", new String(encodedData)));
}
try {
Field profileField = skullMeta.getClass().getDeclaredField("profile");
profileField.setAccessible(true);
profileField.set(skullMeta, gameProfile);
itemStack.setItemMeta(skullMeta);
} catch (IllegalAccessException | NoSuchFieldException ex) {
ex.printStackTrace();
}
return itemStack;
}
}

View File

@ -4,12 +4,12 @@ import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.core.nms.NmsManager;
import com.songoda.core.nms.nbt.NBTItem;
import com.songoda.core.utils.ItemUtils;
import com.songoda.core.utils.TextUtils;
import com.songoda.epicvouchers.EpicVouchers;
import com.songoda.epicvouchers.events.ForceRedeemEvent;
import com.songoda.epicvouchers.events.VoucherReceiveEvent;
import com.songoda.epicvouchers.menus.ConfirmMenu;
import com.songoda.epicvouchers.utils.SkullUtils;
import lombok.experimental.Accessors;
import org.bukkit.Bukkit;
import org.bukkit.Material;
@ -121,7 +121,7 @@ public class Voucher {
}
if (texture != null && !texture.isEmpty() && CompatibleMaterial.PLAYER_HEAD.getMaterial() == material) {
item = SkullUtils.customTexture(itemStack, texture);
item = ItemUtils.getCustomHead(texture);
}
NBTItem nbtItem = NmsManager.getNbt().of(item);

View File

@ -1,15 +1,14 @@
package com.songoda.epicvouchers.voucher;
import com.songoda.core.compatibility.CompatibleSound;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.core.utils.TextUtils;
import com.songoda.epicvouchers.EpicVouchers;
import com.songoda.epicvouchers.events.VoucherRedeemEvent;
import com.songoda.epicvouchers.libraries.BountifulAPI;
import com.songoda.epicvouchers.listeners.PlayerCommandListener;
import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.Effect;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
@ -128,7 +127,7 @@ public class VoucherExecutor {
}
if (voucher.getActionBar() != null && !voucher.getActionBar().isEmpty()) {
String actionbar = voucher.getActionBar().replaceAll("%player%", name).replaceAll("%voucher%", voucher.getName(true));
BountifulAPI.sendActionBar(player, actionbar);
instance.getLocale().newMessage(actionbar).sendActionBar(player);
}
if (voucher.getTitle() != null && !voucher.getTitle().isEmpty()) {
@ -139,7 +138,11 @@ public class VoucherExecutor {
int stay = voucher.getTitleStay();
int fadeout = voucher.getTitleFadeOut();
BountifulAPI.sendTitle(player, fadein, stay, fadeout, title, subtitle);
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11)) {
player.sendTitle(title, subtitle, fadein, stay, fadeout);
} else {
player.sendTitle(title, subtitle);
}
}
if (voucher.getSound() != null && !voucher.getSound().isEmpty()) {