Skip to content

Commit

Permalink
修正NMS部分,实测1.7及以下无法兼容Action
Browse files Browse the repository at this point in the history
优化部分检测
  • Loading branch information
0XPYEX0 committed Oct 17, 2021
1 parent 5bcc83e commit debb615
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,11 @@ public void onEnable() {
return;
}
}
NMSAll.nmsVer = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
logger.info("当前服务端NMS版本: " + NMSAll.nmsVer); //v1_8_R3

if (NMSAll.nmsVer.equalsIgnoreCase("v1_8_R1") || NMSAll.nmsVer.startsWith("v1_7_")) {
NMSAll.isOldVer = true;
}
logger.info("成功加载配置文件");

HandleConfig.functionWL = HandleConfig.config.getJSONObject("FunctionsWhitelist").getBoolean("Enable");
HandleConfig.noCostWL = HandleConfig.config.getJSONObject("NoCostFoodWhitelist").getBoolean("Enable");

logger.info("成功加载配置文件");
logger.info("已成功加载!");

}
Expand Down Expand Up @@ -110,6 +104,10 @@ public void run() {
cancel();
return;
}
if (player.getAllowFlight()) {
cancel();
return;
}
if (player.isOnGround()) {
cancel();
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public static boolean loadConfig() {
FlyWithFood.logger.warning("你的服务器不支持直接发送Action信息!");
FlyWithFood.logger.warning("将尝试调用NMS以发送Action信息");
NMSAll.shouldUseNMSAction = true;
FlyWithFood.logger.info("当前服务端NMS版本: " + NMSAll.nmsVer);
}
}
FlyWithFood.startCheck();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package me.xpyex.plugin.flywithfood.bukkit.reflections;

import org.bukkit.Bukkit;

public class NMSAll {
public static String nmsVer;
public static boolean isOldVer = false;
public static String nmsVer = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
public static boolean shouldUseNMSAction = false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,66 +2,155 @@

import me.xpyex.plugin.flywithfood.bukkit.FlyWithFood;
import me.xpyex.plugin.flywithfood.bukkit.config.HandleConfig;

import org.bukkit.Bukkit;
import org.bukkit.entity.Player;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class NMSUtil {

/*
* 代码来源ActionBarAPI,为了兼容旧版本
* 其开源地址: https://github.com/connorlinfoot/ActionBarAPI
* 其SpigotMC页面地址: https://www.spigotmc.org/resources/actionbarapi-1-8-1-14-2.1315/
* 非常感谢这位作者
* NMS版本号
*/
public static void sendActionBar(Player player, String text) {

if (!player.isOnline()) {
return; // Player may have logged out
}
/*
* CraftBukkit类下面的getHandle方法 用于获取NMS对象
*/
private static final Method getHandleMethod;

/*
* NMS的EntityPlayer类中的playerConnection 用于获取PlayerConnection对象
*/
private static final Field playerConnectionField;

/*
* NMS的PlayerConnection类中的sendPacket 用于发包
*/
private static final Method sendPacketMethod;

/*
* NMS的ChatComponentText类中的构造方法 发包的内容
* ChatComponentText(String)
*/
private static final Constructor<?> chatComponentTextConstructor;

/*
* NMS的PacketPlayOutChatClass类中的构造方法 数据包的构造方法
* >1.8 PacketPlayOutChat(IChatBaseComponent, ChatMessageType)
* =1.8 PacketPlayOutChat(IChatBaseComponent, byte)
* <1.8 PacketPlayOutChat(IChatBaseComponent, int)
*/
private static Constructor<?> packetPlayOutChatClassConstructor;

/*
* NMS的PacketPlayOutChatClass构造方法中的第二个参数
* ChatMessageType消息类型 在低版本中使用的是byte类型
*/
private static Object chatMessageType;

/*
* 初始化
*/
static {
try {
Class<?> craftPlayerClass = Class.forName("org.bukkit.craftbukkit." + NMSAll.nmsVer + ".entity.CraftPlayer");
Object craftPlayer = craftPlayerClass.cast(player);
Object packet;
Class<?> packetPlayOutChatClass = Class.forName("net.minecraft.server." + NMSAll.nmsVer + ".PacketPlayOutChat");
Class<?> packetClass = Class.forName("net.minecraft.server." + NMSAll.nmsVer + ".Packet");
if (NMSAll.isOldVer) {
Class<?> chatSerializerClass = Class.forName("net.minecraft.server." + NMSAll.nmsVer + ".ChatSerializer");
Class<?> iChatBaseComponentClass = Class.forName("net.minecraft.server." + NMSAll.nmsVer + ".IChatBaseComponent");
Method m3 = chatSerializerClass.getDeclaredMethod("a", String.class);
Object cbc = iChatBaseComponentClass.cast(m3.invoke(chatSerializerClass, "{\"text\": \"" + text + "\"}"));
packet = packetPlayOutChatClass.getConstructor(new Class<?>[]{iChatBaseComponentClass, byte.class}).newInstance(cbc, (byte) 2);
} else {
Class<?> chatComponentTextClass = Class.forName("net.minecraft.server." + NMSAll.nmsVer + ".ChatComponentText");
Class<?> iChatBaseComponentClass = Class.forName("net.minecraft.server." + NMSAll.nmsVer + ".IChatBaseComponent");
// 这三个是发包需要的
Class<?> craftPlayerClass = getClass("org.bukkit.craftbukkit." + NMSAll.nmsVer + ".entity.CraftPlayer");
getHandleMethod = craftPlayerClass.getMethod("getHandle");
Class<?> entityPlayerClass = getNMSClass("EntityPlayer");
playerConnectionField = entityPlayerClass.getField("playerConnection");
Class<?> playerConnectionClass = getNMSClass("PlayerConnection");
sendPacketMethod = playerConnectionClass.getMethod("sendPacket", getNMSClass("Packet"));
// 下面是创建数据包需要的
Class<?> chatComponentTextClass = getNMSClass("ChatComponentText");
chatComponentTextConstructor = chatComponentTextClass.getConstructor(String.class);
Class<?> packetPlayOutChatClass = getNMSClass("PacketPlayOutChat");
Class<?> iChatBaseComponentClass = getNMSClass("IChatBaseComponent");
// 这个try只捕获 getNMSClass 方法内的异常 Class Not Found.
try {
// 如果有这个类 那么版本 > 1.8
Class<?> chatMessageTypeClass = getNMSClass("ChatMessageType");
chatMessageType = chatMessageTypeClass.getField("GAME_INFO").get(null);
packetPlayOutChatClassConstructor = packetPlayOutChatClass.getConstructor(iChatBaseComponentClass, chatMessageTypeClass);
} catch (IllegalArgumentException e) {
// 否则就是 <= 1.8
try {
Class<?> chatMessageTypeClass = Class.forName("net.minecraft.server." + NMSAll.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(text);
packet = packetPlayOutChatClass.getConstructor(new Class<?>[]{iChatBaseComponentClass, chatMessageTypeClass}).newInstance(chatCompontentText, chatMessageType);
} catch (ClassNotFoundException cnfe) {
Object chatCompontentText = chatComponentTextClass.getConstructor(new Class<?>[]{String.class}).newInstance(text);
packet = packetPlayOutChatClass.getConstructor(new Class<?>[]{iChatBaseComponentClass, byte.class}).newInstance(chatCompontentText, (byte) 2);
chatMessageType = (byte) 2;
packetPlayOutChatClassConstructor = packetPlayOutChatClass.getConstructor(iChatBaseComponentClass, byte.class);
} catch (NoSuchMethodException e1) { //1.7
chatMessageType = 2;
packetPlayOutChatClassConstructor = packetPlayOutChatClass.getConstructor(iChatBaseComponentClass, int.class);
}
}
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();
} catch (ReflectiveOperationException e) {
HandleConfig.enableAction = false;
FlyWithFood.logger.warning("你的服务器不支持发送Action信息!");
FlyWithFood.logger.warning("请在配置文件禁用Action信息!");
throw new IllegalStateException(e);
}
}

private NMSUtil() {
throw new UnsupportedOperationException("此类不允许实例化");
}

/**
* 发送ActionBar信息
*
* @param player 玩家
* @param text 文本
*/
public static void sendActionBar(Player player, String text) {
Bukkit.getScheduler().runTaskAsynchronously(FlyWithFood.INSTANCE, () -> {
try {
// 正常流程 -> ((CraftPlayer) player).getHandle().playerConnection.sendPacket(Packet)
Object packet = generateActionBarPacket(text);
Object nmsPlayer = getHandleMethod.invoke(player);
Object playerConnection = playerConnectionField.get(nmsPlayer);
sendPacketMethod.invoke(playerConnection, packet);
} catch (Exception e) {
e.printStackTrace();
HandleConfig.enableAction = false;
FlyWithFood.logger.warning("你的服务器不支持发送Action信息!");
FlyWithFood.logger.warning("请在配置文件禁用Action信息!");
}
});
}

/**
* 生成一个ActionBar包
*
* @param text 文本
* @return 数据包
*/
public static Object generateActionBarPacket(String text) throws ReflectiveOperationException {
Object chatComponentText = chatComponentTextConstructor.newInstance(text);
return packetPlayOutChatClassConstructor.newInstance(chatComponentText, chatMessageType);
}

/**
* 获取一个NMS的类
*
* @param className 类名
* @return Class
*/
private static Class<?> getNMSClass(String className) {
return getClass("net.minecraft.server." + NMSAll.nmsVer + "." + className);
}

/**
* 获取类
*
* @param name 完整类名
* @return 类
*/
public static Class<?> getClass(String name) {
try {
return Class.forName(name);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("Class Not Found.", e);
}
}
}
20 changes: 10 additions & 10 deletions src/main/java/me/xpyex/plugin/flywithfood/bukkit/utils/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,28 +26,28 @@ public static void sendFWFMsg(CommandSender target, FWFMsgType msgType) {
return;
}
if (HandleConfig.enableRawMsg) {
String rawDisableMsg = HandleConfig.config.getJSONObject("Languages").getJSONObject("RawMsg").getString(msgType.getValue());
if (!rawDisableMsg.isEmpty()) {
target.sendMessage(getColorfulMsg(rawDisableMsg));
String rawMsg = HandleConfig.config.getJSONObject("Languages").getJSONObject("RawMsg").getString(msgType.getValue());
if (!rawMsg.isEmpty()) {
target.sendMessage(getColorfulMsg(rawMsg));
}
}
if (!(target instanceof Player)) {
return;
}
if (HandleConfig.enableAction) {
String actionDisableMsg = HandleConfig.config.getJSONObject("Languages").getJSONObject("ActionMsg").getString(msgType.getValue());
if (!actionDisableMsg.isEmpty()) {
String actionMsg = HandleConfig.config.getJSONObject("Languages").getJSONObject("ActionMsg").getString(msgType.getValue());
if (!actionMsg.isEmpty()) {
if (NMSAll.shouldUseNMSAction) {
NMSUtil.sendActionBar((Player) target, getColorfulMsg(actionDisableMsg));
NMSUtil.sendActionBar((Player) target, getColorfulMsg(actionMsg));
} else {
((Player) target).spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(getColorfulMsg(actionDisableMsg)));
((Player) target).spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(getColorfulMsg(actionMsg)));
}
}
}
if (HandleConfig.enableTitle) {
String titleDisableMsg = HandleConfig.config.getJSONObject("Languages").getJSONObject("TitleMsg").getString(msgType.getValue());
if (!titleDisableMsg.isEmpty()) {
String[] titles = titleDisableMsg.split("\\u005c\\u006e");
String titleMsg = HandleConfig.config.getJSONObject("Languages").getJSONObject("TitleMsg").getString(msgType.getValue());
if (!titleMsg.isEmpty()) {
String[] titles = titleMsg.split("\\u005c\\u006e");
if (titles.length > 2) {
FlyWithFood.logger.warning("Title数量错误!最多仅有2行!");
HandleConfig.enableTitle = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public static void startCheck() {
player.offer(Keys.IS_FLYING, false);
Utils.sendFWFMsg(player, FWFMsgType.CanNotFly);
Scheduler.execute(() ->
new CancellingTimerTask(player)
new FallDamageTimer(player)
)
.delayTicks(4)
.intervalTicks(4)
Expand All @@ -124,9 +124,9 @@ public static void startCheck() {
}
}

class CancellingTimerTask implements Consumer<Task> {
class FallDamageTimer implements Consumer<Task> {
private final Player player;
public CancellingTimerTask(Player player) {
public FallDamageTimer(Player player) {
this.player = player;
}
@Override
Expand All @@ -135,6 +135,10 @@ public void accept(Task task) {
task.cancel();
return;
}
if (player.get(Keys.CAN_FLY).orElse(false)) {
task.cancel();
return;
}
if (player.isOnGround()) {
task.cancel();
return;
Expand Down

0 comments on commit debb615

Please sign in to comment.