TabooLib v4.27

+ 修复 TFunction 注解会因为 onEnable/onDisable 方法不存在而报错的问题。
+ 优化 TabooLibServer 模块,现在可以在服务器内启动终端,不需要另外运行插件。
+ 优化 PacketParser 模块,现在会自动注册含有 @PacketType 注解的类,和 @TListener 一样方便。
+ 增加 @PacketValue 注解,使用该直接的成员变量会被自动序列化。

“最近开发的机器人用到了通讯网,所以本次更新对该模块进行了反复测试和优化”
This commit is contained in:
坏黑 2018-09-12 00:56:38 +08:00
parent 5b5a96464f
commit de98b51c57
11 changed files with 177 additions and 72 deletions

View File

@ -6,7 +6,7 @@
<groupId>me.skymc</groupId>
<artifactId>TabooLib</artifactId>
<version>4.26</version>
<version>4.27</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

View File

@ -23,6 +23,7 @@ import me.skymc.taboolib.permission.PermissionUtils;
import me.skymc.taboolib.playerdata.DataUtils;
import me.skymc.taboolib.skript.SkriptHandler;
import me.skymc.taboolib.socket.TabooLibClient;
import me.skymc.taboolib.socket.TabooLibServer;
import me.skymc.taboolib.string.language2.Language2;
import me.skymc.taboolib.support.SupportPlaceholder;
import me.skymc.taboolib.timecycle.TimeCycleManager;
@ -163,6 +164,10 @@ public class Main extends JavaPlugin {
}
} catch (IOException ignored) {
}
// 本地通讯网络终端
if (getConfig().getBoolean("SERVER")) {
TabooLibServer.main(new String[0]);
}
// 本地通讯网络
TabooLibClient.init();
}

View File

@ -40,14 +40,10 @@ public class TFunctionLoader implements Listener {
TFunction function = (TFunction) pluginClass.getAnnotation(TFunction.class);
try {
Method method = pluginClass.getDeclaredMethod(function.enable());
if (method == null) {
continue;
}
method.setAccessible(true);
method.invoke(pluginClass.newInstance());
pluginFunction.computeIfAbsent(plugin.getName(), name -> new ArrayList<>()).add(pluginClass);
} catch (Exception e) {
e.printStackTrace();
} catch (Exception ignored) {
}
}
}
@ -65,13 +61,9 @@ public class TFunctionLoader implements Listener {
TFunction function = (TFunction) pluginClass.getAnnotation(TFunction.class);
try {
Method method = pluginClass.getDeclaredMethod(function.disable());
if (method == null) {
continue;
}
method.setAccessible(true);
method.invoke(pluginClass.newInstance());
} catch (Exception e) {
e.printStackTrace();
} catch (Exception ignored) {
}
}
}

View File

@ -1,11 +1,13 @@
package me.skymc.taboolib.socket;
·import me.skymc.taboolib.TabooLib;
import me.skymc.taboolib.other.NumberUtils;
import me.skymc.taboolib.socket.packet.Packet;
import me.skymc.taboolib.socket.packet.PacketSerializer;
import me.skymc.taboolib.socket.packet.impl.PacketHeartbeat;
import me.skymc.taboolib.socket.packet.impl.PacketQuit;
import me.skymc.taboolib.socket.server.ClientConnection;
import org.bukkit.Bukkit;
import java.io.IOException;
import java.net.ServerSocket;
@ -58,17 +60,22 @@ public class TabooLibServer {
client.entrySet().stream().filter(connection -> !connection.getValue().isAlive()).map(connection -> new PacketQuit(connection.getKey(), "Lost connection")).forEach(TabooLibServer::sendPacket);
}, 0, 1, TimeUnit.SECONDS);
while (true) {
try {
Socket socket = server.accept();
ClientConnection connection = new ClientConnection(socket);
client.put(socket.getPort(), connection);
executorService.execute(connection);
println("Client accepted: " + socket.getPort() + " online: " + client.size());
} catch (Exception e) {
println("Client accept failed: " + e.toString());
/*
异步接收连接请求
*/
Executors.newSingleThreadScheduledExecutor().execute(() -> {
while (true) {
try {
Socket socket = server.accept();
ClientConnection connection = new ClientConnection(socket);
client.put(socket.getPort(), connection);
executorService.execute(connection);
println("Client accepted: " + socket.getPort() + " online: " + client.size());
} catch (Exception e) {
println("Client accept failed: " + e.toString());
}
}
}
});
}
public static void sendPacket(Packet packet) {
@ -89,10 +96,9 @@ public class TabooLibServer {
}
public static void println(Object obj) {
System.out.println("[" + infoFormat.format(System.currentTimeMillis()) + " INFO]: " + obj);
System.out.println(TabooLib.isSpigot() ? obj : "[" + infoFormat.format(System.currentTimeMillis()) + " INFO]: " + obj);
}
public static Optional<Map.Entry<Integer, ClientConnection>> getConnection(int port) {
return client.entrySet().stream().filter(entry -> entry.getKey().equals(port)).findFirst();
}

View File

@ -4,6 +4,7 @@ import com.google.gson.JsonObject;
import me.skymc.taboolib.fileutils.FileUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
@ -31,6 +32,43 @@ public class PacketParser {
try {
Packet packetObject = (Packet) packetFind.get().getConstructor(Integer.TYPE).newInstance(json.get("port").getAsInt());
packetObject.unSerialize(json);
Arrays.stream(packetObject.getClass().getDeclaredFields()).filter(field -> field.isAnnotationPresent(PacketValue.class)).forEach(field -> {
field.setAccessible(true);
try {
switch (field.getType().getSimpleName().toLowerCase()) {
case "double":
field.set(packetObject, json.get(field.getName()).getAsDouble());
break;
case "long":
field.set(packetObject, json.get(field.getName()).getAsLong());
break;
case "short":
field.set(packetObject, json.get(field.getName()).getAsShort());
break;
case "boolean":
field.set(packetObject, json.get(field.getName()).getAsBoolean());
break;
case "string":
field.set(packetObject, json.get(field.getName()).getAsString());
break;
case "number":
field.set(packetObject, json.get(field.getName()).getAsNumber());
break;
case "int":
case "integer":
field.set(packetObject, json.get(field.getName()).getAsInt());
break;
case "char":
case "character":
field.set(packetObject, json.get(field.getName()).getAsCharacter());
break;
default:
System.out.println("UnSerialize: Invalid packet value: " + field.getName());
}
} catch (Exception e) {
e.printStackTrace();
}
});
return packetObject;
} catch (Exception e) {
e.printStackTrace();

View File

@ -3,22 +3,88 @@ package me.skymc.taboolib.socket.packet;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import me.skymc.taboolib.TabooLib;
import me.skymc.taboolib.TabooLibLoader;
import me.skymc.taboolib.listener.TListener;
import me.skymc.taboolib.socket.packet.impl.PacketEmpty;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.event.server.PluginEnableEvent;
import org.bukkit.plugin.Plugin;
import java.lang.reflect.Field;
import java.util.Arrays;
/**
* @Author sky
* @Since 2018-08-22 23:32
*/
public class PacketSerializer {
@TListener
public class PacketSerializer implements Listener {
private static PacketParser parser = new PacketParser();
public PacketSerializer() {
loadPacket();
}
@EventHandler
public void onEnable(PluginEnableEvent e) {
loadPacket(e.getPlugin());
}
@EventHandler
public void onDisable(PluginDisableEvent e) {
unloadPacket(e.getPlugin());
}
public static void loadPacket() {
Arrays.stream(Bukkit.getPluginManager().getPlugins()).forEach(PacketSerializer::loadPacket);
}
public static void loadPacket(Plugin plugin) {
if (TabooLib.isTabooLib(plugin) || TabooLib.isDependTabooLib(plugin)) {
TabooLibLoader.getPluginClasses(plugin).ifPresent(classes -> classes.stream().filter(pluginClass -> pluginClass.isAnnotationPresent(PacketType.class)).forEach(pluginClass -> parser.getPackets().add(pluginClass)));
}
}
public static void unloadPacket() {
Arrays.stream(Bukkit.getPluginManager().getPlugins()).forEach(PacketSerializer::unloadPacket);
}
public static void unloadPacket(Plugin plugin) {
if (TabooLib.isTabooLib(plugin) || TabooLib.isDependTabooLib(plugin)) {
TabooLibLoader.getPluginClasses(plugin).ifPresent(classes -> classes.stream().filter(pluginClass -> pluginClass.isAnnotationPresent(PacketType.class)).forEach(pluginClass -> parser.getPackets().remove(pluginClass)));
}
}
public static String serialize(Packet packet) {
JsonObject json = new JsonObject();
packet.serialize(json);
json.addProperty("uid", packet.getUid());
json.addProperty("port", packet.getPort());
json.addProperty("packet", packet.getClass().getAnnotation(PacketType.class).name());
packet.serialize(json);
Arrays.stream(packet.getClass().getDeclaredFields()).filter(field -> field.isAnnotationPresent(PacketValue.class)).forEach(field -> {
field.setAccessible(true);
try {
Object obj = field.get(packet);
if (obj instanceof Number) {
json.addProperty(field.getName(), (Number) obj);
} else if (obj instanceof Boolean) {
json.addProperty(field.getName(), (Boolean) obj);
} else if (obj instanceof String) {
json.addProperty(field.getName(), (String) obj);
} else if (obj instanceof Character) {
json.addProperty(field.getName(), (Character) obj);
} else {
System.out.println("Serialize: Invalid packet value: " + field.getName());
}
} catch (Exception e) {
e.printStackTrace();
}
});
return json.toString();
}

View File

@ -0,0 +1,25 @@
package me.skymc.taboolib.socket.packet;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 使用该注解的成员变量
* 将会被自动序列化
*
* 仅限以下类型
* - Number
* - String
* - Boolean
* - Character
*
* @Author sky
* @Since 2018-08-22 23:09
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PacketValue {
}

View File

@ -1,10 +1,9 @@
package me.skymc.taboolib.socket.packet.impl;
import com.google.gson.JsonObject;
import com.ilummc.tlib.resources.TLocale;
import me.skymc.taboolib.socket.TabooLibServer;
import me.skymc.taboolib.socket.packet.Packet;
import me.skymc.taboolib.socket.packet.PacketType;
import me.skymc.taboolib.socket.packet.PacketValue;
import org.bukkit.Bukkit;
/**
@ -14,6 +13,7 @@ import org.bukkit.Bukkit;
@PacketType(name = "command")
public class PacketCommand extends Packet {
@PacketValue
private String command;
public PacketCommand(int port) {
@ -34,18 +34,4 @@ public class PacketCommand extends Packet {
TabooLibServer.sendPacket(new PacketMessage(0, "Invalid arguments."));
}
}
@Override
public void readOnClient() {
}
@Override
public void serialize(JsonObject json) {
json.addProperty("command", this.command);
}
@Override
public void unSerialize(JsonObject json) {
this.command = json.get("command").getAsString();
}
}

View File

@ -5,6 +5,7 @@ import com.ilummc.tlib.resources.TLocale;
import me.skymc.taboolib.socket.TabooLibServer;
import me.skymc.taboolib.socket.packet.Packet;
import me.skymc.taboolib.socket.packet.PacketType;
import me.skymc.taboolib.socket.packet.PacketValue;
import org.bukkit.Bukkit;
/**
@ -14,6 +15,7 @@ import org.bukkit.Bukkit;
@PacketType(name = "message")
public class PacketMessage extends Packet {
@PacketValue
private String message;
public PacketMessage(int port) {
@ -39,14 +41,4 @@ public class PacketMessage extends Packet {
public void readOnClient() {
TLocale.sendToConsole("COMMUNICATION.PACKET-MESSAGE", String.valueOf(getPort()), message);
}
@Override
public void serialize(JsonObject json) {
json.addProperty("message", message);
}
@Override
public void unSerialize(JsonObject json) {
message = json.get("message").getAsString();
}
}

View File

@ -1,10 +1,10 @@
package me.skymc.taboolib.socket.packet.impl;
import com.google.gson.JsonObject;
import com.ilummc.tlib.resources.TLocale;
import me.skymc.taboolib.socket.TabooLibServer;
import me.skymc.taboolib.socket.packet.Packet;
import me.skymc.taboolib.socket.packet.PacketType;
import me.skymc.taboolib.socket.packet.PacketValue;
/**
* @Author sky
@ -13,6 +13,7 @@ import me.skymc.taboolib.socket.packet.PacketType;
@PacketType(name = "quit")
public class PacketQuit extends Packet {
@PacketValue
private String message;
public PacketQuit(int port) {
@ -43,14 +44,4 @@ public class PacketQuit extends Packet {
public void readOnClient() {
TLocale.sendToConsole("COMMUNICATION.CLIENT-QUITED", String.valueOf(getPort()));
}
@Override
public void serialize(JsonObject json) {
json.addProperty("message", message);
}
@Override
public void unSerialize(JsonObject json) {
message = json.get("message").getAsString();
}
}

View File

@ -13,16 +13,6 @@ DATAURL:
# 物品数据(来自 ItemSave 插件)
ITEMDIR: 'plugins/Skript/scripts/config/item.yml'
# 是否启用调试模式
# 启用后将收到来自其他插件的调试信息
DEBUG: false
# 网络连接测试地址
TEST-URL: 'aliyun.com'
# 下载依赖时启用的线程数
DOWNLOAD-POOL-SIZE: 4
# 语言文件相关设置
LOCALE:
# 加载语言文件的顺序
@ -34,6 +24,20 @@ LOCALE:
# 如果需要开启仍然可以在语言文件中加入 papi: true
USE_PAPI: false
# 是否启用调试模式
# 启用后将收到来自其他插件的调试信息
DEBUG: false
# 是否在当前服务器启用交流网终端
# 启用后将会收到大量调试信息, 不建议使用
SERVER: false
# 网络连接测试地址
TEST-URL: 'aliyun.com'
# 下载依赖时启用的线程数
DOWNLOAD-POOL-SIZE: 4
# 玩家列表TAB-API是否根据前缀排序
TABLIST-SORT: true