2016-07-28 05:53:27 +00:00
|
|
|
package pw.yumc.YumCore.bukkit.compatible;
|
|
|
|
|
|
|
|
import java.lang.reflect.Constructor;
|
2016-08-08 12:39:35 +00:00
|
|
|
import java.lang.reflect.Field;
|
2016-07-28 05:53:27 +00:00
|
|
|
import java.lang.reflect.Method;
|
|
|
|
import java.util.Arrays;
|
|
|
|
import java.util.Collection;
|
|
|
|
import java.util.UUID;
|
|
|
|
|
|
|
|
import org.bukkit.Bukkit;
|
2016-08-08 12:39:35 +00:00
|
|
|
import org.bukkit.ChatColor;
|
2016-07-28 05:53:27 +00:00
|
|
|
import org.bukkit.OfflinePlayer;
|
|
|
|
import org.bukkit.Server;
|
2016-08-08 12:39:35 +00:00
|
|
|
import org.bukkit.World;
|
|
|
|
import org.json.simple.JSONObject;
|
2016-07-28 05:53:27 +00:00
|
|
|
|
|
|
|
import com.google.common.base.Charsets;
|
|
|
|
|
|
|
|
import pw.yumc.YumCore.bukkit.Log;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Bukkit兼容类
|
|
|
|
*
|
|
|
|
* @since 2016年7月23日 下午1:04:56
|
|
|
|
* @author 喵♂呜
|
|
|
|
*/
|
|
|
|
public class C {
|
2016-08-08 12:39:35 +00:00
|
|
|
private static Class<?> nmsChatSerializer;
|
|
|
|
private static Class<?> nmsIChatBaseComponent;
|
|
|
|
private static Class<?> packetType;
|
|
|
|
private static Class<?> packetActions;
|
|
|
|
private static Class<?> packetTitle;
|
|
|
|
|
|
|
|
private static Method getHandle;
|
|
|
|
|
|
|
|
private static String version;
|
|
|
|
private static Field playerConnection;
|
|
|
|
private static Method sendPacket;
|
|
|
|
static {
|
|
|
|
try {
|
2016-08-09 09:33:36 +00:00
|
|
|
version = getNMSVersion();
|
2016-08-08 12:39:35 +00:00
|
|
|
final boolean newversion = Integer.parseInt(version.split("_")[1]) > 7;
|
2016-08-09 09:33:36 +00:00
|
|
|
nmsChatSerializer = Class.forName(a(newversion ? "IChatBaseComponent$ChatSerializer" : "ChatSerializer"));
|
2016-08-08 12:39:35 +00:00
|
|
|
nmsIChatBaseComponent = Class.forName(a("IChatBaseComponent"));
|
|
|
|
packetType = Class.forName(a("PacketPlayOutChat"));
|
2016-08-09 09:33:36 +00:00
|
|
|
packetActions = Class.forName(a(newversion ? "PacketPlayOutTitle$EnumTitleAction" : "EnumTitleAction"));
|
2016-08-08 12:39:35 +00:00
|
|
|
packetTitle = Class.forName(a("PacketPlayOutTitle"));
|
2016-08-09 09:33:36 +00:00
|
|
|
final Class<?> typeCraftPlayer = Class.forName(b("entity.CraftPlayer"));
|
2016-08-08 12:39:35 +00:00
|
|
|
final Class<?> typeNMSPlayer = Class.forName(a("EntityPlayer"));
|
|
|
|
final Class<?> typePlayerConnection = Class.forName(a("PlayerConnection"));
|
|
|
|
getHandle = typeCraftPlayer.getMethod("getHandle");
|
|
|
|
playerConnection = typeNMSPlayer.getField("playerConnection");
|
|
|
|
sendPacket = typePlayerConnection.getMethod("sendPacket", Class.forName(a("Packet")));
|
2016-09-19 08:19:03 +00:00
|
|
|
} catch (final Exception e) {
|
2016-08-09 09:33:36 +00:00
|
|
|
Log.warning(C.class.getSimpleName() + " 兼容性工具初始化失败 可能造成部分功能不可用!");
|
2016-09-19 08:19:03 +00:00
|
|
|
Log.debug(e);
|
2016-08-08 12:39:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-19 08:49:34 +00:00
|
|
|
private C() {
|
|
|
|
}
|
|
|
|
|
2016-08-08 12:39:35 +00:00
|
|
|
public static String a(final String str) {
|
|
|
|
return "net.minecraft.server." + version + "." + str;
|
|
|
|
}
|
|
|
|
|
2016-08-09 09:33:36 +00:00
|
|
|
public static String b(final String str) {
|
|
|
|
return "org.bukkit.craftbukkit." + version + "." + str;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 获得NMS版本号
|
|
|
|
*
|
|
|
|
* @return NMS版本号
|
|
|
|
*/
|
|
|
|
public static String getNMSVersion() {
|
|
|
|
return Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3];
|
|
|
|
}
|
|
|
|
|
2016-08-08 12:39:35 +00:00
|
|
|
public static class ActionBar {
|
2016-09-19 08:49:34 +00:00
|
|
|
private ActionBar() {
|
|
|
|
}
|
|
|
|
|
2016-08-08 12:39:35 +00:00
|
|
|
/**
|
|
|
|
* 公告发送ActionBar
|
|
|
|
*
|
|
|
|
* @param message
|
|
|
|
* 需要发送的消息
|
|
|
|
*/
|
|
|
|
public static void broadcast(final String message) {
|
|
|
|
for (final org.bukkit.entity.Player player : C.Player.getOnlinePlayers()) {
|
|
|
|
send(player, message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 公告发送ActionBar
|
|
|
|
*
|
|
|
|
* @param message
|
|
|
|
* 需要发送的消息
|
|
|
|
* @param times
|
|
|
|
* 需要显示的时间
|
|
|
|
*/
|
|
|
|
public static void broadcast(final String message, final int times) {
|
|
|
|
new Thread(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
int time = times;
|
|
|
|
do {
|
|
|
|
for (final org.bukkit.entity.Player player : C.Player.getOnlinePlayers()) {
|
|
|
|
send(player, message);
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
Thread.sleep(1000);
|
|
|
|
} catch (final InterruptedException e) {
|
2016-09-19 08:49:34 +00:00
|
|
|
// Ignore
|
2016-08-08 12:39:35 +00:00
|
|
|
}
|
|
|
|
time--;
|
|
|
|
} while (time > 0);
|
|
|
|
}
|
|
|
|
}).start();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 公告发送ActionBar(分世界)
|
|
|
|
*
|
|
|
|
* @param world
|
|
|
|
* 需要发送的世界
|
|
|
|
* @param message
|
|
|
|
* 需要发送的消息
|
|
|
|
* @param times
|
|
|
|
* 需要显示的时间
|
|
|
|
*/
|
|
|
|
public static void broadcast(final World world, final String message, final int times) {
|
|
|
|
new Thread(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
int time = times;
|
|
|
|
do {
|
|
|
|
for (final org.bukkit.entity.Player player : C.Player.getOnlinePlayers()) {
|
|
|
|
if (player.getWorld().getName().equalsIgnoreCase(world.getName())) {
|
|
|
|
send(player, message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
Thread.sleep(1000);
|
|
|
|
} catch (final InterruptedException e) {
|
2016-09-19 08:49:34 +00:00
|
|
|
// Ignore
|
2016-08-08 12:39:35 +00:00
|
|
|
}
|
|
|
|
time--;
|
|
|
|
} while (time > 0);
|
|
|
|
|
|
|
|
}
|
2016-09-19 08:49:34 +00:00
|
|
|
}).start();
|
2016-08-08 12:39:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 给玩家发送ActionBar消息
|
|
|
|
*
|
|
|
|
* @param receivingPacket
|
|
|
|
* 接受信息的玩家
|
|
|
|
* @param msg
|
|
|
|
* ActionBar信息
|
|
|
|
*/
|
|
|
|
public static void send(final org.bukkit.entity.Player receivingPacket, final String msg) {
|
|
|
|
Object packet = null;
|
|
|
|
try {
|
|
|
|
final Object serialized = nmsChatSerializer.getMethod("a", String.class).invoke(null, "{\"text\":\"" + ChatColor.translateAlternateColorCodes('&', JSONObject.escape(msg)) + "\"}");
|
|
|
|
if (!version.contains("1_7")) {
|
|
|
|
packet = packetType.getConstructor(nmsIChatBaseComponent, byte.class).newInstance(serialized, (byte) 2);
|
|
|
|
} else {
|
|
|
|
packet = packetType.getConstructor(nmsIChatBaseComponent, int.class).newInstance(serialized, 2);
|
|
|
|
}
|
|
|
|
final Object player = getHandle.invoke(receivingPacket);
|
|
|
|
final Object connection = playerConnection.get(player);
|
|
|
|
sendPacket.invoke(connection, packet);
|
|
|
|
} catch (final Exception ex) {
|
2016-09-19 08:49:34 +00:00
|
|
|
Log.debug("ActionBar发包错误 " + version, ex);
|
2016-08-08 12:39:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 给玩家发送ActionBar消息
|
|
|
|
*
|
|
|
|
* @param receivingPacket
|
|
|
|
* 接受信息的玩家
|
|
|
|
* @param msg
|
|
|
|
* 需要发送的消息
|
|
|
|
* @param times
|
|
|
|
* 需要显示的时间
|
|
|
|
*/
|
|
|
|
public static void send(final org.bukkit.entity.Player receivingPacket, final String msg, final int times) {
|
|
|
|
new Thread(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
int time = times;
|
|
|
|
do {
|
|
|
|
send(receivingPacket, msg);
|
|
|
|
try {
|
|
|
|
Thread.sleep(1000);
|
|
|
|
} catch (final InterruptedException e) {
|
2016-09-19 08:49:34 +00:00
|
|
|
// Ignore
|
2016-08-08 12:39:35 +00:00
|
|
|
}
|
|
|
|
time--;
|
|
|
|
} while (time > 0);
|
|
|
|
}
|
|
|
|
}).start();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-28 05:53:27 +00:00
|
|
|
/**
|
|
|
|
* Bukkit Player兼容类
|
|
|
|
*
|
|
|
|
* @since 2016年7月23日 下午4:33:40
|
|
|
|
* @author 喵♂呜
|
|
|
|
*/
|
|
|
|
public static class Player {
|
|
|
|
private static Class<?> gameProfileClass;
|
|
|
|
private static Constructor<?> gameProfileConstructor;
|
|
|
|
private static Constructor<?> craftOfflinePlayerConstructor;
|
|
|
|
private static Method getOnlinePlayers;
|
|
|
|
static {
|
|
|
|
try {
|
|
|
|
// getOnlinePlayers start
|
|
|
|
getOnlinePlayers = Bukkit.class.getDeclaredMethod("getOnlinePlayers");
|
2016-08-09 04:20:56 +00:00
|
|
|
if (getOnlinePlayers.getReturnType() != org.bukkit.entity.Player[].class) {
|
2016-07-28 05:53:27 +00:00
|
|
|
for (final Method method : Bukkit.class.getDeclaredMethods()) {
|
2016-08-09 04:20:56 +00:00
|
|
|
if (method.getReturnType() == org.bukkit.entity.Player[].class && method.getName().endsWith("getOnlinePlayers")) {
|
2016-07-28 05:53:27 +00:00
|
|
|
getOnlinePlayers = method;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// getOnlinePlayers end
|
2016-09-19 08:19:03 +00:00
|
|
|
} catch (final Exception e) {
|
2016-09-12 02:35:55 +00:00
|
|
|
Log.warning(Player.class.getSimpleName() + "兼容性工具初始化失败 可能造成部分功能不可用!");
|
|
|
|
}
|
|
|
|
try {
|
2016-07-28 05:53:27 +00:00
|
|
|
// getOfflinePlayer start
|
|
|
|
try {
|
|
|
|
gameProfileClass = Class.forName("net.minecraft.util.com.mojang.authlib.GameProfile");
|
2016-09-12 02:35:55 +00:00
|
|
|
} catch (final Exception e) {
|
2016-07-28 05:53:27 +00:00
|
|
|
try {
|
|
|
|
gameProfileClass = Class.forName("com.mojang.authlib.GameProfile");
|
2016-09-12 02:35:55 +00:00
|
|
|
} catch (final Exception e1) {
|
2016-07-28 05:53:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
gameProfileConstructor = gameProfileClass.getDeclaredConstructor(new Class[] { UUID.class, String.class });
|
|
|
|
gameProfileConstructor.setAccessible(true);
|
|
|
|
final Class<? extends Server> craftServer = Bukkit.getServer().getClass();
|
|
|
|
final Class<?> craftOfflinePlayer = Class.forName(craftServer.getName().replace("CraftServer", "CraftOfflinePlayer"));
|
|
|
|
craftOfflinePlayerConstructor = craftOfflinePlayer.getDeclaredConstructor(new Class[] { craftServer, gameProfileClass });
|
|
|
|
craftOfflinePlayerConstructor.setAccessible(true);
|
|
|
|
// getOfflinePlayer end
|
2016-09-12 02:35:55 +00:00
|
|
|
} catch (final Exception e) {
|
2016-09-19 08:19:03 +00:00
|
|
|
Log.debug(e);
|
2016-07-28 05:53:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-19 08:49:34 +00:00
|
|
|
private Player() {
|
|
|
|
}
|
|
|
|
|
2016-07-28 05:53:27 +00:00
|
|
|
/**
|
|
|
|
* 获取离线玩家(跳过网络获取)
|
|
|
|
*
|
|
|
|
* @param playerName
|
|
|
|
* 玩家名称
|
|
|
|
* @return {@link OfflinePlayer}
|
|
|
|
*/
|
|
|
|
public static OfflinePlayer getOfflinePlayer(final String playerName) {
|
|
|
|
try {
|
|
|
|
final Object gameProfile = gameProfileConstructor.newInstance(new Object[] { UUID.nameUUIDFromBytes(("OfflinePlayer:" + playerName).getBytes(Charsets.UTF_8)), playerName });
|
|
|
|
final Object offlinePlayer = craftOfflinePlayerConstructor.newInstance(new Object[] { Bukkit.getServer(), gameProfile });
|
|
|
|
return (OfflinePlayer) offlinePlayer;
|
2016-09-19 08:19:03 +00:00
|
|
|
} catch (final Exception e) {
|
2016-07-28 05:53:27 +00:00
|
|
|
return Bukkit.getOfflinePlayer(playerName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 获取在线玩家
|
|
|
|
*
|
|
|
|
* @return 在线玩家
|
|
|
|
*/
|
|
|
|
public static Collection<? extends org.bukkit.entity.Player> getOnlinePlayers() {
|
|
|
|
try {
|
|
|
|
return Arrays.asList((org.bukkit.entity.Player[]) getOnlinePlayers.invoke(null));
|
2016-09-19 08:19:03 +00:00
|
|
|
} catch (final Exception e) {
|
2016-07-28 05:53:27 +00:00
|
|
|
return Bukkit.getOnlinePlayers();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-08-08 12:39:35 +00:00
|
|
|
|
|
|
|
public static class Title {
|
2016-09-19 08:49:34 +00:00
|
|
|
private Title() {
|
|
|
|
}
|
|
|
|
|
2016-09-13 09:01:46 +00:00
|
|
|
/**
|
|
|
|
* 发送Title公告
|
|
|
|
*
|
|
|
|
* @param title
|
|
|
|
* 标题
|
|
|
|
* @param subtitle
|
|
|
|
* 子标题
|
|
|
|
*/
|
|
|
|
public static void broadcast(final String title, final String subtitle) {
|
|
|
|
for (final org.bukkit.entity.Player player : Player.getOnlinePlayers()) {
|
|
|
|
send(player, title, subtitle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 发送Title公告
|
|
|
|
*
|
|
|
|
* @param title
|
|
|
|
* 标题
|
|
|
|
* @param subtitle
|
|
|
|
* 子标题
|
2016-09-19 07:19:59 +00:00
|
|
|
* @param fadeInTime
|
|
|
|
* 淡入时间
|
|
|
|
* @param stayTime
|
|
|
|
* 持续时间
|
|
|
|
* @param fadeOutTime
|
|
|
|
* 淡出时间
|
2016-09-13 09:01:46 +00:00
|
|
|
*/
|
|
|
|
public static void broadcast(final String title, final String subtitle, final int fadeInTime, final int stayTime, final int fadeOutTime) {
|
|
|
|
for (final org.bukkit.entity.Player player : Player.getOnlinePlayers()) {
|
|
|
|
send(player, title, subtitle, fadeInTime, stayTime, fadeOutTime);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 发送Title公告
|
|
|
|
*
|
|
|
|
* @param world
|
|
|
|
* 世界
|
|
|
|
* @param title
|
|
|
|
* 标题
|
|
|
|
* @param subtitle
|
|
|
|
* 子标题
|
|
|
|
*/
|
|
|
|
public static void broadcast(final World world, final String title, final String subtitle) {
|
|
|
|
for (final org.bukkit.entity.Player player : Player.getOnlinePlayers()) {
|
|
|
|
if (player.getWorld().getName().equalsIgnoreCase(world.getName())) {
|
|
|
|
send(player, title, subtitle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-08 12:39:35 +00:00
|
|
|
/**
|
|
|
|
* 重置玩家的Title
|
|
|
|
*
|
|
|
|
* @param recoverPlayer
|
|
|
|
* 接受的玩家
|
|
|
|
* @throws Exception
|
|
|
|
* 异常
|
|
|
|
*/
|
2016-08-09 04:20:56 +00:00
|
|
|
public static void reset(final org.bukkit.entity.Player recoverPlayer) throws Exception {
|
2016-08-08 12:39:35 +00:00
|
|
|
// Send timings first
|
|
|
|
final Object player = getHandle.invoke(recoverPlayer);
|
|
|
|
final Object connection = playerConnection.get(player);
|
|
|
|
final Object[] actions = packetActions.getEnumConstants();
|
|
|
|
final Object packet = packetTitle.getConstructor(packetActions, nmsIChatBaseComponent).newInstance(actions[4], null);
|
|
|
|
sendPacket.invoke(connection, packet);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 发送Titile(默认时间 1 2 1)
|
|
|
|
*
|
|
|
|
* @param receivingPacket
|
|
|
|
* 接受信息的玩家
|
|
|
|
* @param title
|
|
|
|
* 标题
|
|
|
|
* @param subtitle
|
|
|
|
* 子标题
|
|
|
|
*/
|
2016-08-09 04:20:56 +00:00
|
|
|
public static void send(final org.bukkit.entity.Player receivingPacket, final String title, final String subtitle) {
|
2016-08-08 12:39:35 +00:00
|
|
|
send(receivingPacket, title, subtitle, 1, 2, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 发送Titile
|
|
|
|
*
|
|
|
|
* @param receivingPacket
|
|
|
|
* 接受信息的玩家
|
|
|
|
* @param title
|
|
|
|
* 标题
|
|
|
|
* @param subtitle
|
|
|
|
* 子标题
|
|
|
|
* @param fadeInTime
|
|
|
|
* 淡入时间
|
|
|
|
* @param stayTime
|
|
|
|
* 持续时间
|
|
|
|
* @param fadeOutTime
|
|
|
|
* 淡出时间
|
|
|
|
*/
|
2016-08-09 04:20:56 +00:00
|
|
|
public static void send(final org.bukkit.entity.Player receivingPacket, final String title, final String subtitle, final int fadeInTime, final int stayTime, final int fadeOutTime) {
|
2016-08-08 12:39:35 +00:00
|
|
|
if (packetTitle != null) {
|
|
|
|
try {
|
|
|
|
// First reset previous settings
|
|
|
|
reset(receivingPacket);
|
|
|
|
// Send timings first
|
|
|
|
final Object player = getHandle.invoke(receivingPacket);
|
|
|
|
final Object connection = playerConnection.get(player);
|
|
|
|
final Object[] actions = packetActions.getEnumConstants();
|
|
|
|
Object packet = null;
|
|
|
|
// Send if set
|
|
|
|
if ((fadeInTime != -1) && (fadeOutTime != -1) && (stayTime != -1)) {
|
2016-09-12 02:35:55 +00:00
|
|
|
packet = packetTitle.getConstructor(packetActions, nmsIChatBaseComponent, Integer.TYPE, Integer.TYPE, Integer.TYPE).newInstance(actions[2], null, fadeInTime * 20, stayTime * 20, fadeOutTime * 20);
|
2016-08-08 12:39:35 +00:00
|
|
|
sendPacket.invoke(connection, packet);
|
|
|
|
}
|
|
|
|
// Send title
|
2016-08-10 02:39:37 +00:00
|
|
|
Object serialized = nmsChatSerializer.getMethod("a", String.class).invoke(null, "{\"text\":\"" + ChatColor.translateAlternateColorCodes('&', title) + "\"}");
|
2016-08-08 12:39:35 +00:00
|
|
|
packet = packetTitle.getConstructor(packetActions, nmsIChatBaseComponent).newInstance(actions[0], serialized);
|
|
|
|
sendPacket.invoke(connection, packet);
|
2016-09-19 08:19:03 +00:00
|
|
|
if (!"".equals(subtitle)) {
|
2016-08-08 12:39:35 +00:00
|
|
|
// Send subtitle if present
|
2016-08-10 02:39:37 +00:00
|
|
|
serialized = nmsChatSerializer.getMethod("a", String.class).invoke(null, "{\"text\":\"" + ChatColor.translateAlternateColorCodes('&', subtitle) + "\"}");
|
2016-08-08 12:39:35 +00:00
|
|
|
packet = packetTitle.getConstructor(packetActions, nmsIChatBaseComponent).newInstance(actions[1], serialized);
|
|
|
|
sendPacket.invoke(connection, packet);
|
|
|
|
}
|
2016-09-19 08:19:03 +00:00
|
|
|
} catch (final Exception e) {
|
2016-09-19 08:49:34 +00:00
|
|
|
Log.debug(e);
|
2016-08-08 12:39:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-07-28 05:53:27 +00:00
|
|
|
}
|