From df51e398b1ed9fe5fa516da4c477ff2581654815 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=9D=8F=E9=BB=91?= Date: Sun, 28 Oct 2018 16:24:46 +0800 Subject: [PATCH] + TPacket + TJson --- pom.xml | 2 +- .../taboolib/common/inject/TInjectLoader.java | 10 + .../taboolib/common/json/TJsonArray.java | 348 ++++++++++++++++++ .../taboolib/common/json/TJsonObject.java | 251 +++++++++++++ .../common/packet/TPacketHandler.java | 77 ++++ .../common/packet/TPacketListener.java | 19 + .../packet/channel/ChannelExecutor.java | 74 ++++ .../channel/InternalChannelExecutor.java | 28 ++ 8 files changed, 808 insertions(+), 1 deletion(-) create mode 100644 src/main/java/me/skymc/taboolib/common/json/TJsonArray.java create mode 100644 src/main/java/me/skymc/taboolib/common/json/TJsonObject.java create mode 100644 src/main/java/me/skymc/taboolib/common/packet/TPacketHandler.java create mode 100644 src/main/java/me/skymc/taboolib/common/packet/TPacketListener.java create mode 100644 src/main/java/me/skymc/taboolib/common/packet/channel/ChannelExecutor.java create mode 100644 src/main/java/me/skymc/taboolib/common/packet/channel/InternalChannelExecutor.java diff --git a/pom.xml b/pom.xml index bdc462e..c67aa35 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ me.skymc TabooLib - 4.58 + 4.6 UTF-8 diff --git a/src/main/java/me/skymc/taboolib/common/inject/TInjectLoader.java b/src/main/java/me/skymc/taboolib/common/inject/TInjectLoader.java index 0c0bcdb..99728c6 100644 --- a/src/main/java/me/skymc/taboolib/common/inject/TInjectLoader.java +++ b/src/main/java/me/skymc/taboolib/common/inject/TInjectLoader.java @@ -5,6 +5,8 @@ import com.ilummc.tlib.logger.TLogger; import me.skymc.taboolib.TabooLibLoader; import me.skymc.taboolib.commands.builder.SimpleCommandBuilder; import me.skymc.taboolib.common.configuration.TConfiguration; +import me.skymc.taboolib.common.packet.TPacketHandler; +import me.skymc.taboolib.common.packet.TPacketListener; import org.bukkit.plugin.Plugin; import java.lang.reflect.Field; @@ -28,6 +30,14 @@ public class TInjectLoader implements TabooLibLoader.Loader { e.printStackTrace(); } }); + // TPacketListener Inject + injectTypes.put(TPacketListener.class, (plugin, field, args) -> { + try { + TPacketHandler.addListener(plugin, ((TPacketListener) field.get(null))); + } catch (Exception e) { + e.printStackTrace(); + } + }); // TConfiguration Inject injectTypes.put(TConfiguration.class, (plugin, field, args) -> { if (args.length == 0) { diff --git a/src/main/java/me/skymc/taboolib/common/json/TJsonArray.java b/src/main/java/me/skymc/taboolib/common/json/TJsonArray.java new file mode 100644 index 0000000..9851af1 --- /dev/null +++ b/src/main/java/me/skymc/taboolib/common/json/TJsonArray.java @@ -0,0 +1,348 @@ +package me.skymc.taboolib.common.json; + +import com.google.gson.*; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Spliterator; +import java.util.function.Consumer; + +/** + * @Author 坏黑 + * @Since 2018-10-27 23:46 + */ +public class TJsonArray implements Iterable { + + private JsonArray jsonArray; + + TJsonArray(JsonArray jsonArray) { + this.jsonArray = jsonArray; + } + + /** + * 从 Json 原代码中获取 + * + * @param json 源代码 + * @return {@link TJsonArray} + * @throws JsonParseException if the specified text is not valid JSON + * @throws IllegalStateException This is not a JSON Array. + */ + public static TJsonArray fromJson(String json) throws JsonParseException, IllegalStateException { + return new TJsonArray(new JsonParser().parse(json).getAsJsonArray()); + } + + /** + * 从 JsonArray 创建 + * + * @param jsonArray JsonArray 对象 + * @return {@link TJsonObject} + */ + public static TJsonArray fromJsonArray(JsonArray jsonArray) { + return new TJsonArray(jsonArray); + } + + /** + * 添加成员 + * + * @param obj 成员 + */ + public void add(TJsonObject obj) { + jsonArray.add(obj.asOriginJsonElement()); + } + + /** + * 添加成员 + * + * @param obj 成员 + */ + public void add(Boolean obj) { + jsonArray.add(obj); + } + + /** + * 添加成员 + * + * @param obj 成员 + */ + public void add(Character obj) { + jsonArray.add(obj); + } + + /** + * 添加成员 + * + * @param obj 成员 + */ + public void add(Number obj) { + jsonArray.add(obj); + } + + /** + * 添加成员 + * + * @param obj 成员 + */ + public void add(String obj) { + jsonArray.add(obj); + } + + /** + * 添加所有成员 + * + * @param array 成员集合 + */ + public void addAll(TJsonArray array) { + jsonArray.add(array.asOriginJsonArray()); + } + + /** + * 设置成员 + * + * @param index 位置 + * @param obj 成员 + */ + public void set(int index, TJsonObject obj) { + jsonArray.set(index, obj.asOriginJsonElement()); + } + + /** + * 设置成员 + * + * @param index 位置 + * @param obj 成员 + */ + public void set(int index, Boolean obj) { + jsonArray.set(index, new JsonPrimitive(obj)); + } + + /** + * 设置成员 + * + * @param index 位置 + * @param obj 成员 + */ + public void set(int index, Number obj) { + jsonArray.set(index, new JsonPrimitive(obj)); + } + + /** + * 设置成员 + * + * @param index 位置 + * @param obj 成员 + */ + public void set(int index, String obj) { + jsonArray.set(index, new JsonPrimitive(obj)); + } + + /** + * 移除成员 + * + * @param obj 成员 + */ + public void remove(JsonElement obj) { + jsonArray.remove(obj); + } + + /** + * 移除成员 + * + * @param obj 成员 + */ + public void remove(Boolean obj) { + jsonArray.remove(new JsonPrimitive(obj)); + } + + /** + * 移除成员 + * + * @param obj 成员 + */ + public void remove(Number obj) { + jsonArray.remove(new JsonPrimitive(obj)); + } + + /** + * 移除成员 + * + * @param obj 成员 + */ + public void remove(String obj) { + jsonArray.remove(new JsonPrimitive(obj)); + } + + /** + * 含有成员 + * + * @param obj 成员 + * @return boolean + */ + public boolean contains(JsonElement obj) { + return jsonArray.contains(obj); + } + + /** + * 含有成员 + * + * @param obj 成员 + * @return boolean + */ + public boolean contains(Boolean obj) { + return jsonArray.contains(new JsonPrimitive(obj)); + } + + /** + * 含有成员 + * + * @param obj 成员 + * @return boolean + */ + public boolean contains(Number obj) { + return jsonArray.contains(new JsonPrimitive(obj)); + } + + /** + * 含有成员 + * + * @param obj 成员 + * @return boolean + */ + public boolean contains(String obj) { + return jsonArray.contains(new JsonPrimitive(obj)); + } + + /** + * 获取成员,默认值:null + * + * @param index 序号 + * @return {@link TJsonObject} + */ + public TJsonObject getJsonObject(int index) { + return jsonArray.get(index).isJsonObject() ? TJsonObject.fromJsonObject(jsonArray.get(index).getAsJsonObject()) : null; + } + + /** + * 获取成员,默认值:null + * + * @param index 序号 + * @return {@link TJsonArray} + */ + public TJsonArray getJsonArray(int index) { + return jsonArray.get(index).isJsonArray() ? TJsonArray.fromJsonArray(jsonArray.get(index).getAsJsonArray()) : null; + } + + /** + * 获取成员,默认值:false + * + * @param index 序号 + * @return boolean + */ + public Boolean getBoolean(int index) { + return jsonArray.get(index).isJsonPrimitive() && jsonArray.get(index).getAsBoolean(); + } + + /** + * 获取成员 + * + * @param index 序号 + * @param def 默认值 + * @return boolean + */ + public Boolean getBoolean(int index, boolean def) { + return jsonArray.get(index).isJsonPrimitive() ? jsonArray.get(index).getAsBoolean() : def; + } + + /** + * 获取成员,默认值:0 + * + * @param index 序号 + * @return number + */ + public Number getNumber(int index) { + return jsonArray.get(index).isJsonPrimitive() ? jsonArray.get(index).getAsNumber() : 0; + } + + /** + * 获取成员 + * + * @param index 序号 + * @param def 默认值 + * @return number + */ + public Number getNumber(int index, Number def) { + return jsonArray.get(index).isJsonPrimitive() ? jsonArray.get(index).getAsNumber() : def; + } + + /** + * 获取成员,默认值:null + * + * @param index 序号 + * @return string + */ + public String getString(int index) { + return jsonArray.get(index).isJsonPrimitive() ? jsonArray.get(index).getAsString() : null; + } + + /** + * 获取成员 + * + * @param index 序号 + * @param def 默认值 + * @return string + */ + public String getString(int index, String def) { + return jsonArray.get(index).isJsonPrimitive() ? jsonArray.get(index).getAsString() : def; + } + + /** + * 成员数量 + * + * @return int + */ + public int size() { + return jsonArray.size(); + } + + /** + * 转换为 JsonArray 类型 + * + * @return {@link JsonArray} + */ + public JsonArray asOriginJsonArray() { + return jsonArray; + } + + @Override + public Iterator iterator() { + List jsonObjectList = new ArrayList<>(); + for (JsonElement jsonElement : jsonArray) { + jsonObjectList.add(TJsonObject.fromJsonObject(jsonElement)); + } + return jsonObjectList.iterator(); + } + + @Override + public void forEach(Consumer action) { + List jsonObjectList = new ArrayList<>(); + for (JsonElement jsonElement : jsonArray) { + jsonObjectList.add(TJsonObject.fromJsonObject(jsonElement)); + } + jsonObjectList.forEach(action); + } + + @Override + public Spliterator spliterator() { + List jsonObjectList = new ArrayList<>(); + for (JsonElement jsonElement : jsonArray) { + jsonObjectList.add(TJsonObject.fromJsonObject(jsonElement)); + } + return jsonObjectList.spliterator(); + } + + @Override + public String toString() { + return jsonArray.toString(); + } + +} diff --git a/src/main/java/me/skymc/taboolib/common/json/TJsonObject.java b/src/main/java/me/skymc/taboolib/common/json/TJsonObject.java new file mode 100644 index 0000000..6f0380f --- /dev/null +++ b/src/main/java/me/skymc/taboolib/common/json/TJsonObject.java @@ -0,0 +1,251 @@ +package me.skymc.taboolib.common.json; + +import com.google.gson.*; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @Author 坏黑 + * @Since 2018-10-27 23:06 + */ +public class TJsonObject { + + private JsonElement jsonObject; + + TJsonObject(JsonElement jsonObject) { + this.jsonObject = jsonObject; + } + + /** + * 从 Json 原代码中获取 + * + * @param json 源代码 + * @return {@link TJsonObject} + * @throws JsonParseException if the specified text is not valid JSON + */ + public static TJsonObject fromJson(String json) throws JsonParseException { + return new TJsonObject(new JsonParser().parse(json)); + } + + /** + * 从 JsonElement 创建 + * + * @param jsonElement JsonElement 对象 + * @return {@link TJsonObject} + */ + public static TJsonObject fromJsonObject(JsonElement jsonElement) { + return new TJsonObject(jsonElement); + } + + /** + * 是否含有该节点 + * + * @param path 地址 + * @return boolean + */ + public boolean contains(String path) { + return get(path) != null; + } + + /** + * 获取文本,默认值:空 + * + * @param path 地址 + * @return String + */ + public String getString(String path) { + return getString(path, ""); + } + + /** + * 获取文本 + * + * @param path 地址 + * @param def 默认值 + * @return String + */ + public String getString(String path, String def) { + JsonElement jsonElement = get(path); + return !(jsonElement instanceof JsonPrimitive) || jsonElement == null ? def : jsonElement.getAsString(); + } + + /** + * 获取数字,默认值:0 + * + * @param path 地址 + * @return Number + */ + public Number getNumber(String path) { + return getNumber(path, 0); + } + + /** + * 获取数字 + * + * @param path 地址 + * @param def 默认值 + * @return Number + */ + public Number getNumber(String path, Number def) { + JsonElement jsonElement = get(path); + return !(jsonElement instanceof JsonPrimitive) || jsonElement == null ? def : jsonElement.getAsNumber(); + } + + /** + * 获取布尔值,默认值:false + * + * @param path 地址 + * @return boolean + */ + public boolean getBoolean(String path) { + return getBoolean(path, false); + } + + /** + * 获取布尔值 + * + * @param path 地址 + * @param def 默认值 + * @return boolean + */ + public boolean getBoolean(String path, boolean def) { + JsonElement jsonElement = get(path); + return !(jsonElement instanceof JsonPrimitive) || jsonElement == null ? def : jsonElement.getAsBoolean(); + } + + /** + * 获取 TJsonObject 对象,默认值:null + * + * @param path 地址 + * @return {@link TJsonObject} + */ + public TJsonObject getJsonObject(String path) { + JsonElement jsonElement = get(path); + return !(jsonElement instanceof JsonObject) || jsonElement == null ? null : TJsonObject.fromJsonObject(jsonElement); + } + + /** + * 获取 TJsonArray 对象,默认值:null + * + * @param path 地址 + * @return {@link TJsonArray} + */ + public TJsonArray getJsonArray(String path) { + JsonElement jsonElement = get(path); + return !(jsonElement instanceof JsonArray) || jsonElement == null ? null : TJsonArray.fromJsonArray((JsonArray) jsonElement); + } + + /** + * 获取所有成员 + * + * @return {@link Map.Entry} + */ + public Set> entrySet() { + return !(jsonObject instanceof JsonObject) ? new HashSet<>() : ((JsonObject) jsonObject).entrySet().stream().map(jsonElementEntry -> new HashMap.SimpleEntry<>(jsonElementEntry.getKey(), fromJsonObject(jsonElementEntry.getValue()))).collect(Collectors.toCollection(HashSet::new)); + } + + /** + * 获取所有键 + * + * @return {@link Set} + */ + public Set keySet() { + return !(jsonObject instanceof JsonObject) ? new HashSet<>() : ((JsonObject) jsonObject).entrySet().stream().map(Map.Entry::getKey).collect(Collectors.toCollection(HashSet::new)); + } + + /** + * 获取所有值 + * + * @return {@link Collection} + */ + public Collection values() { + return !(jsonObject instanceof JsonObject) ? new ArrayList<>() : ((JsonObject) jsonObject).entrySet().stream().map(jsonElementEntry -> new TJsonObject(jsonElementEntry.getValue())).collect(Collectors.toList()); + } + + /** + * 是否为 JsonObject 类型 + * + * @return boolean + */ + public boolean isJsonObject() { + return jsonObject instanceof JsonObject; + } + + /** + * 是否为 JsonArray 类型 + * + * @return boolean + */ + public boolean isJsonArray() { + return jsonObject instanceof JsonArray; + } + + /** + * 是否为 JsonPrimitive 类型 + * + * @return boolean + */ + public boolean isJsonPrimitive() { + return jsonObject instanceof JsonPrimitive; + } + + /** + * 转换为 JsonObject 类型 + * + * @return {@link JsonObject} + */ + public JsonObject asOriginJsonObject() { + return (JsonObject) jsonObject; + } + + /** + * 转换为 JsonArray 类型 + * + * @return {@link JsonArray} + */ + public JsonArray asOriginJsonArray() { + return (JsonArray) jsonObject; + } + + /** + * 转换为 JsonElement 类型 + * + * @return {@link JsonElement} + */ + public JsonElement asOriginJsonElement() { + return jsonObject; + } + + /** + * 转换为 JsonPrimitive 类型 + * + * @return {@link JsonPrimitive} + */ + public JsonPrimitive asOriginJsonPrimitive() { + return (JsonPrimitive) jsonObject; + } + + @Override + public String toString() { + return jsonObject.toString(); + } + + // ********************************* + // + // Private Methods + // + // ********************************* + + private JsonElement get(String path) { + JsonElement subElement = jsonObject; + for (String p : path.split("/")) { + if (subElement instanceof JsonObject && ((JsonObject) subElement).has(p)) { + subElement = ((JsonObject) subElement).get(p); + } else { + return null; + } + } + return subElement; + } +} diff --git a/src/main/java/me/skymc/taboolib/common/packet/TPacketHandler.java b/src/main/java/me/skymc/taboolib/common/packet/TPacketHandler.java new file mode 100644 index 0000000..8f957ec --- /dev/null +++ b/src/main/java/me/skymc/taboolib/common/packet/TPacketHandler.java @@ -0,0 +1,77 @@ +package me.skymc.taboolib.common.packet; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import me.skymc.taboolib.common.packet.channel.ChannelExecutor; +import me.skymc.taboolib.common.versioncontrol.SimpleVersionControl; +import me.skymc.taboolib.listener.TListener; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.server.PluginDisableEvent; +import org.bukkit.plugin.Plugin; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * @Author 坏黑 + * @Since 2018-10-28 14:52 + */ +@TListener +public class TPacketHandler implements Listener { + + private static Map> packetListeners = Maps.newHashMap(); + private static ChannelExecutor channelExecutor; + + public TPacketHandler() { + try { + channelExecutor = (ChannelExecutor) SimpleVersionControl.create() + .from("v1_8_R3") + .target("me.skymc.taboolib.common.packet.channel.InternalChannelExecutor") + .translate() + .newInstance(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @EventHandler + public void onJoin(PlayerJoinEvent e) { + channelExecutor.addPlayerChannel(e.getPlayer()); + } + + @EventHandler + public void onQuit(PlayerQuitEvent e) { + channelExecutor.removePlayerChannel(e.getPlayer()); + } + + @EventHandler + public void onDisable(PluginDisableEvent e) { + removeListener(e.getPlugin()); + } + + public static void sendPacket(Player player, Object packet) { + channelExecutor.sendPacket(player, packet); + } + + public static void addListener(Plugin plugin, TPacketListener listener) { + packetListeners.computeIfAbsent(plugin.getName(), name -> Lists.newArrayList()).add(listener); + } + + public static void removeListener(Plugin plugin) { + packetListeners.remove(plugin.getName()); + } + + public static void removeListener(Plugin plugin, TPacketListener listener) { + Optional.ofNullable(packetListeners.get(plugin.getName())).ifPresent(list -> list.remove(listener)); + } + + public static Collection> getListeners() { + return packetListeners.values(); + } +} diff --git a/src/main/java/me/skymc/taboolib/common/packet/TPacketListener.java b/src/main/java/me/skymc/taboolib/common/packet/TPacketListener.java new file mode 100644 index 0000000..03bc82b --- /dev/null +++ b/src/main/java/me/skymc/taboolib/common/packet/TPacketListener.java @@ -0,0 +1,19 @@ +package me.skymc.taboolib.common.packet; + +import org.bukkit.entity.Player; + +/** + * @Author 坏黑 + * @Since 2018-10-28 14:35 + */ +public abstract class TPacketListener { + + public boolean onSend(Player player, Object packet) { + return true; + } + + public boolean onReceive(Player player, Object packet) { + return true; + } + +} diff --git a/src/main/java/me/skymc/taboolib/common/packet/channel/ChannelExecutor.java b/src/main/java/me/skymc/taboolib/common/packet/channel/ChannelExecutor.java new file mode 100644 index 0000000..20143cb --- /dev/null +++ b/src/main/java/me/skymc/taboolib/common/packet/channel/ChannelExecutor.java @@ -0,0 +1,74 @@ +package me.skymc.taboolib.common.packet.channel; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPromise; +import me.skymc.taboolib.common.packet.TPacketHandler; +import org.bukkit.entity.Player; + +import java.util.Collection; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * @Author 坏黑 + * @Since 2018-10-28 14:34 + */ +public abstract class ChannelExecutor { + + private ExecutorService addChannelService = Executors.newSingleThreadExecutor(); + private ExecutorService removeChannelService = Executors.newSingleThreadExecutor(); + + public abstract void sendPacket(Player player, Object packet); + + public abstract Channel getPlayerChannel(Player player); + + public void addPlayerChannel(Player player) { + addChannelService.submit(() -> { + getPlayerChannel(player).pipeline().addBefore("packet_handler", "taboolib_packet_handler", new ChannelHandler(player)); + }); + } + + public void removePlayerChannel(Player player) { + removeChannelService.submit(() -> { + Channel playerChannel = getPlayerChannel(player); + if (playerChannel.pipeline().get("taboolib_packet_handler") != null) { + playerChannel.pipeline().remove("taboolib_packet_handler"); + } + }); + } + + class ChannelHandler extends ChannelDuplexHandler { + + private Player player; + + public ChannelHandler(Player player) { + this.player = player; + } + + @Override + public void write(ChannelHandlerContext channelHandlerContext, Object o, ChannelPromise channelPromise) throws Exception { + try { + if (TPacketHandler.getListeners().stream().flatMap(Collection::stream).anyMatch(packetListener -> !packetListener.onSend(player, o))) { + return; + } + } catch (Exception e) { + e.printStackTrace(); + } + super.write(channelHandlerContext, o, channelPromise); + } + + @Override + public void channelRead(ChannelHandlerContext channelHandlerContext, Object o) throws Exception { + try { + if (TPacketHandler.getListeners().stream().flatMap(Collection::stream).anyMatch(packetListener -> !packetListener.onReceive(player, o))) { + return; + } + } catch (Exception e) { + e.printStackTrace(); + } + super.channelRead(channelHandlerContext, o); + } + } +} diff --git a/src/main/java/me/skymc/taboolib/common/packet/channel/InternalChannelExecutor.java b/src/main/java/me/skymc/taboolib/common/packet/channel/InternalChannelExecutor.java new file mode 100644 index 0000000..bbaf842 --- /dev/null +++ b/src/main/java/me/skymc/taboolib/common/packet/channel/InternalChannelExecutor.java @@ -0,0 +1,28 @@ +package me.skymc.taboolib.common.packet.channel; + +import com.ilummc.tlib.logger.TLogger; +import io.netty.channel.Channel; +import net.minecraft.server.v1_8_R3.Packet; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; +import org.bukkit.entity.Player; + +/** + * @Author 坏黑 + * @Since 2018-10-28 15:12 + */ +public class InternalChannelExecutor extends ChannelExecutor { + + @Override + public void sendPacket(Player player, Object packet) { + if (packet instanceof Packet) { + ((CraftPlayer) player).getHandle().playerConnection.sendPacket((Packet) packet); + } else { + TLogger.getGlobalLogger().warn("Invalid packet: " + packet.getClass().getName()); + } + } + + @Override + public Channel getPlayerChannel(Player player) { + return ((CraftPlayer) player).getHandle().playerConnection.networkManager.channel; + } +}