perf: 重写部分代码
This commit is contained in:
@@ -42,7 +42,7 @@ public class BallBukkitAPI extends BallAPI {
|
|||||||
),
|
),
|
||||||
pluginConfig.getString("ball-server.host", "ball.hamster3.cn"),
|
pluginConfig.getString("ball-server.host", "ball.hamster3.cn"),
|
||||||
pluginConfig.getInt("ball-server.port", 58888),
|
pluginConfig.getInt("ball-server.port", 58888),
|
||||||
pluginConfig.getInt("ball-server.nio-thread", 10)
|
pluginConfig.getInt("ball-server.event-loop-thread", 2)
|
||||||
);
|
);
|
||||||
instance = new BallBukkitAPI(config);
|
instance = new BallBukkitAPI(config);
|
||||||
|
|
||||||
|
@@ -4,7 +4,7 @@ debug: false
|
|||||||
ball-server:
|
ball-server:
|
||||||
host: "ball.hamster3.cn"
|
host: "ball.hamster3.cn"
|
||||||
port: 58888
|
port: 58888
|
||||||
nio-thread: 2
|
event-loop-thread: 2
|
||||||
|
|
||||||
server-info:
|
server-info:
|
||||||
# 服务器唯一识别码,最长 32 字符
|
# 服务器唯一识别码,最长 32 字符
|
||||||
|
@@ -29,17 +29,18 @@ public class BallBungeeCordAPI extends BallAPI {
|
|||||||
}
|
}
|
||||||
HamsterBallPlugin plugin = HamsterBallPlugin.getInstance();
|
HamsterBallPlugin plugin = HamsterBallPlugin.getInstance();
|
||||||
Configuration pluginConfig = CoreBungeeCordUtils.getPluginConfig(plugin);
|
Configuration pluginConfig = CoreBungeeCordUtils.getPluginConfig(plugin);
|
||||||
|
|
||||||
BallConfig config = new BallConfig(
|
BallConfig config = new BallConfig(
|
||||||
new BallServerInfo(
|
new BallServerInfo(
|
||||||
pluginConfig.getString("server-info.id"),
|
pluginConfig.getString("server-info.id", "Proxy"),
|
||||||
pluginConfig.getString("server-info.name"),
|
pluginConfig.getString("server-info.name", "Proxy"),
|
||||||
BallServerType.PROXY,
|
BallServerType.PROXY,
|
||||||
pluginConfig.getString("server-info.host", ""),
|
pluginConfig.getString("server-info.host"),
|
||||||
pluginConfig.getInt("server-info.port", 25577)
|
pluginConfig.getInt("server-info.port")
|
||||||
),
|
),
|
||||||
pluginConfig.getString("ball-server.host"),
|
pluginConfig.getString("ball-server.host", "ball.hamster3.cn"),
|
||||||
pluginConfig.getInt("ball-server.port"),
|
pluginConfig.getInt("ball-server.port", 58888),
|
||||||
pluginConfig.getInt("ball-server.nio-thread")
|
pluginConfig.getInt("ball-server.event-loop-thread", 5)
|
||||||
);
|
);
|
||||||
instance = new BallBungeeCordAPI(config);
|
instance = new BallBungeeCordAPI(config);
|
||||||
|
|
||||||
|
@@ -4,7 +4,7 @@ debug: false
|
|||||||
ball-server:
|
ball-server:
|
||||||
host: "ball.hamster3.cn"
|
host: "ball.hamster3.cn"
|
||||||
port: 58888
|
port: 58888
|
||||||
nio-thread: 10
|
event-loop-thread: 10
|
||||||
|
|
||||||
server-info:
|
server-info:
|
||||||
# 服务器唯一识别码,最长 32 字符
|
# 服务器唯一识别码,最长 32 字符
|
||||||
|
@@ -14,6 +14,7 @@ import cn.hamster3.mc.plugin.ball.common.event.server.ServerOfflineEvent;
|
|||||||
import cn.hamster3.mc.plugin.ball.common.event.server.ServerOnlineEvent;
|
import cn.hamster3.mc.plugin.ball.common.event.server.ServerOnlineEvent;
|
||||||
import cn.hamster3.mc.plugin.ball.common.listener.BallListener;
|
import cn.hamster3.mc.plugin.ball.common.listener.BallListener;
|
||||||
import cn.hamster3.mc.plugin.ball.common.listener.ListenerPriority;
|
import cn.hamster3.mc.plugin.ball.common.listener.ListenerPriority;
|
||||||
|
import cn.hamster3.mc.plugin.ball.common.utils.OS;
|
||||||
import cn.hamster3.mc.plugin.core.common.api.CoreAPI;
|
import cn.hamster3.mc.plugin.core.common.api.CoreAPI;
|
||||||
import cn.hamster3.mc.plugin.core.common.data.DisplayMessage;
|
import cn.hamster3.mc.plugin.core.common.data.DisplayMessage;
|
||||||
import cn.hamster3.mc.plugin.core.common.util.CoreUtils;
|
import cn.hamster3.mc.plugin.core.common.util.CoreUtils;
|
||||||
@@ -23,8 +24,7 @@ import io.netty.bootstrap.Bootstrap;
|
|||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
import io.netty.channel.ChannelOption;
|
import io.netty.channel.ChannelOption;
|
||||||
import io.netty.channel.nio.NioEventLoopGroup;
|
import io.netty.channel.EventLoopGroup;
|
||||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -55,7 +55,7 @@ public abstract class BallAPI {
|
|||||||
private final List<BallListener> listeners;
|
private final List<BallListener> listeners;
|
||||||
|
|
||||||
private final Bootstrap bootstrap;
|
private final Bootstrap bootstrap;
|
||||||
private final NioEventLoopGroup executors;
|
private final EventLoopGroup executors;
|
||||||
|
|
||||||
protected boolean enabled;
|
protected boolean enabled;
|
||||||
protected Channel channel;
|
protected Channel channel;
|
||||||
@@ -63,17 +63,23 @@ public abstract class BallAPI {
|
|||||||
protected BallAPI(@NotNull BallConfig config) {
|
protected BallAPI(@NotNull BallConfig config) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.enabled = false;
|
this.enabled = false;
|
||||||
executors = new NioEventLoopGroup(config.getNioThread());
|
|
||||||
|
|
||||||
serverInfo = new ConcurrentHashMap<>();
|
serverInfo = new ConcurrentHashMap<>();
|
||||||
playerInfo = new ConcurrentHashMap<>();
|
playerInfo = new ConcurrentHashMap<>();
|
||||||
listeners = new ArrayList<>();
|
listeners = new ArrayList<>();
|
||||||
|
|
||||||
bootstrap = new Bootstrap();
|
OS currentOS = OS.getCurrentOS();
|
||||||
bootstrap.group(executors)
|
getLogger().info(String.format(
|
||||||
.channel(NioSocketChannel.class)
|
"当前操作系统为: %s. 选择 IO 模式为: %s",
|
||||||
|
currentOS.name(), currentOS.getIOModeName()
|
||||||
|
));
|
||||||
|
|
||||||
|
executors = currentOS.getEventLoopGroup(config.getEventLoopThread());
|
||||||
|
bootstrap = new Bootstrap()
|
||||||
|
.group(executors)
|
||||||
|
.channel(currentOS.getSocketChannel())
|
||||||
.option(ChannelOption.TCP_NODELAY, true)
|
.option(ChannelOption.TCP_NODELAY, true)
|
||||||
.handler(BallChannelInitializer.INSTANCE);
|
.handler(new BallChannelInitializer());
|
||||||
|
|
||||||
addListener(new BallListener() {
|
addListener(new BallListener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -143,6 +149,13 @@ public abstract class BallAPI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConnectRefused() {
|
||||||
|
enabled = false;
|
||||||
|
executors.shutdownGracefully();
|
||||||
|
getLogger().info("连接至服务中心的请求被拒绝,已关闭仓鼠球。");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,9 +178,7 @@ public abstract class BallAPI {
|
|||||||
connect();
|
connect();
|
||||||
|
|
||||||
try (Connection connection = CoreAPI.getInstance().getConnection()) {
|
try (Connection connection = CoreAPI.getInstance().getConnection()) {
|
||||||
|
try (Statement statement = connection.createStatement()) {
|
||||||
{
|
|
||||||
Statement statement = connection.createStatement();
|
|
||||||
statement.execute("CREATE TABLE IF NOT EXISTS `hamster_ball_player_info`(" +
|
statement.execute("CREATE TABLE IF NOT EXISTS `hamster_ball_player_info`(" +
|
||||||
"`uuid` CHAR(36) PRIMARY KEY," +
|
"`uuid` CHAR(36) PRIMARY KEY," +
|
||||||
"`name` VARCHAR(16) NOT NULL," +
|
"`name` VARCHAR(16) NOT NULL," +
|
||||||
@@ -186,53 +197,48 @@ public abstract class BallAPI {
|
|||||||
"`uuid` CHAR(36) NOT NULL," +
|
"`uuid` CHAR(36) NOT NULL," +
|
||||||
"`message` TEXT NOT NULL" +
|
"`message` TEXT NOT NULL" +
|
||||||
") CHARSET utf8mb4;");
|
") CHARSET utf8mb4;");
|
||||||
statement.close();
|
|
||||||
}
|
}
|
||||||
|
try (PreparedStatement statement = connection.prepareStatement(
|
||||||
{
|
"REPLACE INTO `hamster_ball_server_info` VALUES(?, ?, ?, ?, ?);"
|
||||||
PreparedStatement statement = connection.prepareStatement("REPLACE INTO `hamster_ball_server_info` VALUES(?, ?, ?, ?, ?);");
|
)) {
|
||||||
statement.setString(1, localInfo.getId());
|
statement.setString(1, localInfo.getId());
|
||||||
statement.setString(2, localInfo.getName());
|
statement.setString(2, localInfo.getName());
|
||||||
statement.setString(3, localInfo.getType().name());
|
statement.setString(3, localInfo.getType().name());
|
||||||
statement.setString(4, localInfo.getHost());
|
statement.setString(4, localInfo.getHost());
|
||||||
statement.setInt(5, localInfo.getPort());
|
statement.setInt(5, localInfo.getPort());
|
||||||
statement.executeUpdate();
|
statement.executeUpdate();
|
||||||
statement.close();
|
|
||||||
}
|
}
|
||||||
|
try (PreparedStatement statement = connection.prepareStatement(
|
||||||
{
|
"SELECT * FROM `hamster_ball_server_info`;"
|
||||||
PreparedStatement statement = connection.prepareStatement("SELECT * FROM `hamster_ball_server_info`;");
|
)) {
|
||||||
ResultSet set = statement.executeQuery();
|
try (ResultSet set = statement.executeQuery()) {
|
||||||
while (set.next()) {
|
while (set.next()) {
|
||||||
String serverID = set.getString("id");
|
String serverID = set.getString("id");
|
||||||
serverInfo.put(serverID, new BallServerInfo(
|
serverInfo.put(serverID, new BallServerInfo(
|
||||||
serverID,
|
serverID,
|
||||||
set.getString("name"),
|
set.getString("name"),
|
||||||
BallServerType.valueOf(set.getString("type")),
|
BallServerType.valueOf(set.getString("type")),
|
||||||
set.getString("host"),
|
set.getString("host"),
|
||||||
set.getInt("port")
|
set.getInt("port")
|
||||||
));
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
set.close();
|
|
||||||
statement.close();
|
|
||||||
}
|
}
|
||||||
|
try (PreparedStatement statement = connection.prepareStatement(
|
||||||
{
|
"SELECT * FROM `hamster_ball_player_info`;"
|
||||||
PreparedStatement statement = connection.prepareStatement("SELECT * FROM `hamster_ball_player_info`;");
|
)) {
|
||||||
ResultSet set = statement.executeQuery();
|
try (ResultSet set = statement.executeQuery()) {
|
||||||
while (set.next()) {
|
while (set.next()) {
|
||||||
UUID uuid = UUID.fromString(set.getString("uuid"));
|
UUID uuid = UUID.fromString(set.getString("uuid"));
|
||||||
playerInfo.put(uuid, new BallPlayerInfo(uuid,
|
playerInfo.put(uuid, new BallPlayerInfo(uuid,
|
||||||
set.getString("name"),
|
set.getString("name"),
|
||||||
set.getString("game_server"),
|
set.getString("game_server"),
|
||||||
set.getString("proxy_server"),
|
set.getString("proxy_server"),
|
||||||
set.getBoolean("online")
|
set.getBoolean("online")
|
||||||
));
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
set.close();
|
|
||||||
statement.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -15,5 +15,5 @@ public class BallConfig {
|
|||||||
private String host;
|
private String host;
|
||||||
private int port;
|
private int port;
|
||||||
|
|
||||||
private int nioThread;
|
private int eventLoopThread;
|
||||||
}
|
}
|
||||||
|
@@ -16,9 +16,7 @@ import java.util.logging.Level;
|
|||||||
|
|
||||||
@ChannelHandler.Sharable
|
@ChannelHandler.Sharable
|
||||||
public class BallChannelHandler extends SimpleChannelInboundHandler<String> {
|
public class BallChannelHandler extends SimpleChannelInboundHandler<String> {
|
||||||
public static final BallChannelHandler INSTANCE = new BallChannelHandler();
|
public BallChannelHandler() {
|
||||||
|
|
||||||
private BallChannelHandler() {
|
|
||||||
super(true);
|
super(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,6 +25,12 @@ public class BallChannelHandler extends SimpleChannelInboundHandler<String> {
|
|||||||
if ("pong".equals(message)) {
|
if ("pong".equals(message)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if ("connection refused".equals(message)) {
|
||||||
|
for (BallListener listener : BallAPI.getInstance().getListeners()) {
|
||||||
|
listener.onConnectRefused();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
BallMessageInfo info = CoreUtils.GSON.fromJson(message, BallMessageInfo.class);
|
BallMessageInfo info = CoreUtils.GSON.fromJson(message, BallMessageInfo.class);
|
||||||
for (BallListener listener : BallAPI.getInstance().getListeners()) {
|
for (BallListener listener : BallAPI.getInstance().getListeners()) {
|
||||||
try {
|
try {
|
||||||
@@ -186,5 +190,4 @@ public class BallChannelHandler extends SimpleChannelInboundHandler<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -13,22 +13,19 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class BallChannelInitializer extends ChannelInitializer<NioSocketChannel> {
|
public class BallChannelInitializer extends ChannelInitializer<NioSocketChannel> {
|
||||||
public static final BallChannelInitializer INSTANCE = new BallChannelInitializer();
|
public BallChannelInitializer() {
|
||||||
|
|
||||||
private BallChannelInitializer() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initChannel(@NotNull NioSocketChannel channel) {
|
protected void initChannel(@NotNull NioSocketChannel channel) {
|
||||||
channel.pipeline()
|
channel.pipeline()
|
||||||
.addLast(new IdleStateHandler(0, 7, 0, TimeUnit.SECONDS))
|
.addLast(new IdleStateHandler(0, 7, 0, TimeUnit.SECONDS))
|
||||||
.addLast(BallKeepAliveHandler.INSTANCE)
|
.addLast(new BallKeepAliveHandler())
|
||||||
.addLast(new LengthFieldPrepender(8))
|
.addLast(new LengthFieldPrepender(8))
|
||||||
.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 8, 0, 8))
|
.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 8, 0, 8))
|
||||||
.addLast(new StringDecoder(StandardCharsets.UTF_8))
|
.addLast(new StringDecoder(StandardCharsets.UTF_8))
|
||||||
.addLast(new StringEncoder(StandardCharsets.UTF_8))
|
.addLast(new StringEncoder(StandardCharsets.UTF_8))
|
||||||
.addLast(BallChannelHandler.INSTANCE);
|
.addLast(new BallChannelHandler());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -7,12 +7,6 @@ import io.netty.handler.timeout.IdleStateEvent;
|
|||||||
|
|
||||||
@ChannelHandler.Sharable
|
@ChannelHandler.Sharable
|
||||||
public class BallKeepAliveHandler extends ChannelInboundHandlerAdapter {
|
public class BallKeepAliveHandler extends ChannelInboundHandlerAdapter {
|
||||||
public static final BallKeepAliveHandler INSTANCE = new BallKeepAliveHandler();
|
|
||||||
|
|
||||||
private BallKeepAliveHandler() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void userEventTriggered(ChannelHandlerContext context, Object event) throws Exception {
|
public void userEventTriggered(ChannelHandlerContext context, Object event) throws Exception {
|
||||||
if (event instanceof IdleStateEvent) {
|
if (event instanceof IdleStateEvent) {
|
||||||
|
@@ -106,7 +106,7 @@ public class BallMessageInfo {
|
|||||||
* @return json对象
|
* @return json对象
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
public JsonObject saveToJson() {
|
public JsonObject toJson() {
|
||||||
JsonObject object = new JsonObject();
|
JsonObject object = new JsonObject();
|
||||||
object.addProperty("channel", channel);
|
object.addProperty("channel", channel);
|
||||||
object.addProperty("senderID", senderID);
|
object.addProperty("senderID", senderID);
|
||||||
@@ -191,6 +191,6 @@ public class BallMessageInfo {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return saveToJson().toString();
|
return toJson().toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -28,6 +28,9 @@ public interface BallListener {
|
|||||||
default void onConnectException(Throwable throwable) {
|
default void onConnectException(Throwable throwable) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default void onConnectRefused() {
|
||||||
|
}
|
||||||
|
|
||||||
default void onServiceDead() {
|
default void onServiceDead() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,84 @@
|
|||||||
|
package cn.hamster3.mc.plugin.ball.common.utils;
|
||||||
|
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.EventLoopGroup;
|
||||||
|
import io.netty.channel.ServerChannel;
|
||||||
|
import io.netty.channel.epoll.EpollEventLoopGroup;
|
||||||
|
import io.netty.channel.epoll.EpollServerSocketChannel;
|
||||||
|
import io.netty.channel.epoll.EpollSocketChannel;
|
||||||
|
import io.netty.channel.kqueue.KQueueEventLoopGroup;
|
||||||
|
import io.netty.channel.kqueue.KQueueServerSocketChannel;
|
||||||
|
import io.netty.channel.kqueue.KQueueSocketChannel;
|
||||||
|
import io.netty.channel.nio.NioEventLoopGroup;
|
||||||
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||||
|
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public enum OS {
|
||||||
|
WINDOWS,
|
||||||
|
LINUX,
|
||||||
|
MACOS,
|
||||||
|
OTHER;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static OS getCurrentOS() {
|
||||||
|
String s = System.getProperties().get("os.name").toString().toLowerCase();
|
||||||
|
if (s.contains("windows")) {
|
||||||
|
return WINDOWS;
|
||||||
|
}
|
||||||
|
if (s.contains("linux")) {
|
||||||
|
return LINUX;
|
||||||
|
}
|
||||||
|
if (s.contains("mac")) {
|
||||||
|
return MACOS;
|
||||||
|
}
|
||||||
|
return OTHER;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIOModeName() {
|
||||||
|
switch (this) {
|
||||||
|
case LINUX:
|
||||||
|
return "epoll";
|
||||||
|
case MACOS:
|
||||||
|
return "kqueue";
|
||||||
|
default:
|
||||||
|
return "nio";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public EventLoopGroup getEventLoopGroup(int nThread) {
|
||||||
|
switch (this) {
|
||||||
|
case LINUX:
|
||||||
|
return new EpollEventLoopGroup(nThread);
|
||||||
|
case MACOS:
|
||||||
|
return new KQueueEventLoopGroup(nThread);
|
||||||
|
default:
|
||||||
|
return new NioEventLoopGroup(nThread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public Class<? extends Channel> getSocketChannel() {
|
||||||
|
switch (this) {
|
||||||
|
case LINUX:
|
||||||
|
return EpollSocketChannel.class;
|
||||||
|
case MACOS:
|
||||||
|
return KQueueSocketChannel.class;
|
||||||
|
default:
|
||||||
|
return NioSocketChannel.class;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public Class<? extends ServerChannel> getServerSocketChannel() {
|
||||||
|
switch (this) {
|
||||||
|
case LINUX:
|
||||||
|
return EpollServerSocketChannel.class;
|
||||||
|
case MACOS:
|
||||||
|
return KQueueServerSocketChannel.class;
|
||||||
|
default:
|
||||||
|
return NioServerSocketChannel.class;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -5,19 +5,19 @@ evaluationDependsOn(':hamster-ball-common')
|
|||||||
dependencies {
|
dependencies {
|
||||||
apiShade(project(":hamster-ball-common")) { transitive = false }
|
apiShade(project(":hamster-ball-common")) { transitive = false }
|
||||||
|
|
||||||
// https://mvnrepository.com/artifact/org.slf4j/slf4j-api
|
// // https://mvnrepository.com/artifact/org.slf4j/slf4j-api
|
||||||
implementation 'org.slf4j:slf4j-api:2.0.3'
|
// implementation 'org.slf4j:slf4j-api:2.0.3'
|
||||||
|
|
||||||
// https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core
|
// https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core
|
||||||
shade 'org.apache.logging.log4j:log4j-core:2.19.0'
|
implementationShade 'org.apache.logging.log4j:log4j-core:2.19.0'
|
||||||
// https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl
|
// https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl
|
||||||
shade 'org.apache.logging.log4j:log4j-slf4j-impl:2.19.0'
|
implementationShade 'org.apache.logging.log4j:log4j-slf4j-impl:2.19.0'
|
||||||
|
|
||||||
// https://mvnrepository.com/artifact/io.netty/netty-all
|
// https://mvnrepository.com/artifact/io.netty/netty-all
|
||||||
//noinspection GradlePackageUpdate
|
//noinspection GradlePackageUpdate
|
||||||
implementationShade 'io.netty:netty-all:4.1.82.Final'
|
implementationShade 'io.netty:netty-all:4.1.86.Final'
|
||||||
// https://mvnrepository.com/artifact/org.yaml/snakeyaml
|
// https://mvnrepository.com/artifact/org.yaml/snakeyaml
|
||||||
implementationShade 'org.yaml:snakeyaml:1.33'
|
implementationShade 'org.yaml:snakeyaml:2.0'
|
||||||
// https://mvnrepository.com/artifact/com.google.code.gson/gson
|
// https://mvnrepository.com/artifact/com.google.code.gson/gson
|
||||||
//noinspection GradlePackageUpdate
|
//noinspection GradlePackageUpdate
|
||||||
implementationShade 'com.google.code.gson:gson:2.8.9'
|
implementationShade 'com.google.code.gson:gson:2.8.9'
|
||||||
|
@@ -1,49 +1,51 @@
|
|||||||
package cn.hamster3.mc.plugin.ball.server;
|
package cn.hamster3.mc.plugin.ball.server;
|
||||||
|
|
||||||
|
import cn.hamster3.mc.plugin.ball.common.utils.OS;
|
||||||
import cn.hamster3.mc.plugin.ball.server.command.CommandHandler;
|
import cn.hamster3.mc.plugin.ball.server.command.CommandHandler;
|
||||||
import cn.hamster3.mc.plugin.ball.server.config.ServerConfig;
|
import cn.hamster3.mc.plugin.ball.server.config.ServerConfig;
|
||||||
import cn.hamster3.mc.plugin.ball.server.connector.BallServerChannelInitializer;
|
import cn.hamster3.mc.plugin.ball.server.connector.BallServerChannelInitializer;
|
||||||
import io.netty.bootstrap.ServerBootstrap;
|
import io.netty.bootstrap.ServerBootstrap;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
import io.netty.channel.ChannelOption;
|
import io.netty.channel.ChannelOption;
|
||||||
import io.netty.channel.nio.NioEventLoopGroup;
|
import io.netty.channel.EventLoopGroup;
|
||||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.lang.management.ManagementFactory;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
|
|
||||||
public class Bootstrap {
|
public class Bootstrap {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("Bootstrap");
|
private static final Logger LOGGER = LoggerFactory.getLogger("Bootstrap");
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException, InterruptedException {
|
||||||
if (initDefaultFile()) {
|
if (initDefaultFile()) {
|
||||||
LOGGER.info("请重新启动该程序.");
|
LOGGER.info("请重新启动该程序.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ServerConfig.init();
|
ServerConfig.init();
|
||||||
LOGGER.info("配置文件加载完成.");
|
LOGGER.info("配置文件加载完成.");
|
||||||
|
OS currentOS = OS.getCurrentOS();
|
||||||
NioEventLoopGroup loopGroup = new NioEventLoopGroup(ServerConfig.getNioThread());
|
LOGGER.info("当前操作系统为: {}. 选择 IO 模式为: {}", currentOS.name(), currentOS.getIOModeName());
|
||||||
|
EventLoopGroup loopGroup = currentOS.getEventLoopGroup(ServerConfig.getEventLoopThread());
|
||||||
ServerBootstrap bootstrap = new ServerBootstrap()
|
ServerBootstrap bootstrap = new ServerBootstrap()
|
||||||
.group(loopGroup)
|
.group(loopGroup)
|
||||||
.channel(NioServerSocketChannel.class)
|
.channel(currentOS.getServerSocketChannel())
|
||||||
.childOption(ChannelOption.TCP_NODELAY, true)
|
.childOption(ChannelOption.TCP_NODELAY, true)
|
||||||
.childHandler(BallServerChannelInitializer.INSTANCE);
|
.childHandler(new BallServerChannelInitializer());
|
||||||
ChannelFuture channelFuture = bootstrap.bind(ServerConfig.getHost(), ServerConfig.getPort());
|
ChannelFuture future = bootstrap.bind(ServerConfig.getHost(), ServerConfig.getPort());
|
||||||
channelFuture.addListener(future -> {
|
future.await();
|
||||||
if (future.isSuccess()) {
|
if (future.isSuccess()) {
|
||||||
LOGGER.info("服务器已启动. 输入 stop 来关闭该程序.");
|
LOGGER.info("进程信息: {}", ManagementFactory.getRuntimeMXBean().getName());
|
||||||
} else {
|
LOGGER.info("服务器已启动. 输入 stop 来关闭该程序.");
|
||||||
LOGGER.error("仓鼠球服务器启动失败!", future.cause());
|
} else {
|
||||||
loopGroup.shutdownGracefully();
|
LOGGER.error("仓鼠球服务器启动失败!", future.cause());
|
||||||
}
|
loopGroup.shutdownGracefully();
|
||||||
});
|
return;
|
||||||
|
}
|
||||||
CommandHandler.INSTANCE.start(loopGroup);
|
CommandHandler.INSTANCE.start(loopGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
package cn.hamster3.mc.plugin.ball.server.command;
|
package cn.hamster3.mc.plugin.ball.server.command;
|
||||||
|
|
||||||
import io.netty.channel.nio.NioEventLoopGroup;
|
import io.netty.channel.EventLoopGroup;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -9,12 +9,12 @@ import java.util.Scanner;
|
|||||||
public class CommandHandler {
|
public class CommandHandler {
|
||||||
public static final CommandHandler INSTANCE = new CommandHandler();
|
public static final CommandHandler INSTANCE = new CommandHandler();
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("command");
|
private static final Logger LOGGER = LoggerFactory.getLogger("CommandHandler");
|
||||||
private NioEventLoopGroup loopGroup;
|
private EventLoopGroup loopGroup;
|
||||||
|
|
||||||
private boolean started;
|
private boolean started;
|
||||||
|
|
||||||
public void start(NioEventLoopGroup loopGroup) {
|
public void start(EventLoopGroup loopGroup) {
|
||||||
this.loopGroup = loopGroup;
|
this.loopGroup = loopGroup;
|
||||||
|
|
||||||
started = true;
|
started = true;
|
||||||
|
@@ -16,7 +16,7 @@ public final class ServerConfig {
|
|||||||
|
|
||||||
private static String host;
|
private static String host;
|
||||||
private static int port;
|
private static int port;
|
||||||
private static int nioThread;
|
private static int eventLoopThread;
|
||||||
private static boolean enableAcceptList;
|
private static boolean enableAcceptList;
|
||||||
private static List<String> acceptList;
|
private static List<String> acceptList;
|
||||||
|
|
||||||
@@ -33,13 +33,13 @@ public final class ServerConfig {
|
|||||||
|
|
||||||
host = (String) map.get("host");
|
host = (String) map.get("host");
|
||||||
port = (int) map.get("port");
|
port = (int) map.get("port");
|
||||||
nioThread = (int) map.get("nio-thread");
|
eventLoopThread = (int) map.getOrDefault("event-loop-thread", 5);
|
||||||
enableAcceptList = (boolean) map.get("enable-accept-list");
|
enableAcceptList = (boolean) map.get("enable-accept-list");
|
||||||
acceptList = (List<String>) map.get("accept-list");
|
acceptList = (List<String>) map.get("accept-list");
|
||||||
|
|
||||||
LOGGER.info("host: {}", host);
|
LOGGER.info("host: {}", host);
|
||||||
LOGGER.info("port: {}", port);
|
LOGGER.info("port: {}", port);
|
||||||
LOGGER.info("nioThread: {}", nioThread);
|
LOGGER.info("eventLoopThread: {}", eventLoopThread);
|
||||||
LOGGER.info("enableAcceptList: {}", enableAcceptList);
|
LOGGER.info("enableAcceptList: {}", enableAcceptList);
|
||||||
LOGGER.info("acceptList: {}", acceptList);
|
LOGGER.info("acceptList: {}", acceptList);
|
||||||
}
|
}
|
||||||
@@ -52,8 +52,8 @@ public final class ServerConfig {
|
|||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getNioThread() {
|
public static int getEventLoopThread() {
|
||||||
return nioThread;
|
return eventLoopThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isEnableAcceptList() {
|
public static boolean isEnableAcceptList() {
|
||||||
|
@@ -11,10 +11,9 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
@ChannelHandler.Sharable
|
@ChannelHandler.Sharable
|
||||||
public class BallServerChannelHandler extends SimpleChannelInboundHandler<String> {
|
public class BallServerChannelHandler extends SimpleChannelInboundHandler<String> {
|
||||||
public static final BallServerChannelHandler INSTANCE = new BallServerChannelHandler();
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("BallServerChannelHandler");
|
private static final Logger LOGGER = LoggerFactory.getLogger("BallServerChannelHandler");
|
||||||
|
|
||||||
private BallServerChannelHandler() {
|
public BallServerChannelHandler() {
|
||||||
super(true);
|
super(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -20,12 +20,10 @@ import java.util.List;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class BallServerChannelInitializer extends ChannelInitializer<NioSocketChannel> {
|
public class BallServerChannelInitializer extends ChannelInitializer<NioSocketChannel> {
|
||||||
public static final BallServerChannelInitializer INSTANCE = new BallServerChannelInitializer();
|
|
||||||
public static final List<Channel> CHANNELS = new ArrayList<>();
|
public static final List<Channel> CHANNELS = new ArrayList<>();
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("BallServerChannelInitializer");
|
private static final Logger LOGGER = LoggerFactory.getLogger("BallServerChannelInitializer");
|
||||||
|
|
||||||
private BallServerChannelInitializer() {
|
public BallServerChannelInitializer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void broadcastMessage(BallMessageInfo messageInfo) {
|
public static void broadcastMessage(BallMessageInfo messageInfo) {
|
||||||
@@ -50,12 +48,12 @@ public class BallServerChannelInitializer extends ChannelInitializer<NioSocketCh
|
|||||||
|
|
||||||
channel.pipeline()
|
channel.pipeline()
|
||||||
.addLast(new IdleStateHandler(10, 0, 0, TimeUnit.SECONDS))
|
.addLast(new IdleStateHandler(10, 0, 0, TimeUnit.SECONDS))
|
||||||
.addLast(BallServerKeepAliveHandler.INSTANCE)
|
.addLast(new BallServerKeepAliveHandler())
|
||||||
.addLast(new LengthFieldPrepender(8))
|
.addLast(new LengthFieldPrepender(8))
|
||||||
.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 8, 0, 8))
|
.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 8, 0, 8))
|
||||||
.addLast(new StringDecoder(StandardCharsets.UTF_8))
|
.addLast(new StringDecoder(StandardCharsets.UTF_8))
|
||||||
.addLast(new StringEncoder(StandardCharsets.UTF_8))
|
.addLast(new StringEncoder(StandardCharsets.UTF_8))
|
||||||
.addLast(BallServerChannelHandler.INSTANCE);
|
.addLast(new BallServerChannelHandler());
|
||||||
|
|
||||||
synchronized (CHANNELS) {
|
synchronized (CHANNELS) {
|
||||||
CHANNELS.add(channel);
|
CHANNELS.add(channel);
|
||||||
|
@@ -9,11 +9,9 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
@ChannelHandler.Sharable
|
@ChannelHandler.Sharable
|
||||||
public class BallServerKeepAliveHandler extends SimpleUserEventChannelHandler<IdleStateEvent> {
|
public class BallServerKeepAliveHandler extends SimpleUserEventChannelHandler<IdleStateEvent> {
|
||||||
public static final BallServerKeepAliveHandler INSTANCE = new BallServerKeepAliveHandler();
|
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("BallServerKeepAliveHandler");
|
private static final Logger LOGGER = LoggerFactory.getLogger("BallServerKeepAliveHandler");
|
||||||
|
|
||||||
private BallServerKeepAliveHandler() {
|
public BallServerKeepAliveHandler() {
|
||||||
super(true);
|
super(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5,10 +5,10 @@ port: 58888
|
|||||||
|
|
||||||
# 线程池数量
|
# 线程池数量
|
||||||
# 建议设置为全服最大玩家数 / 20
|
# 建议设置为全服最大玩家数 / 20
|
||||||
# 不建议低于 5
|
# 不建议低于 4
|
||||||
nio-thread: 10
|
event-loop-thread: 5
|
||||||
|
|
||||||
# 是否启用IP 白名单
|
# 是否启用 IP 白名单
|
||||||
enable-accept-list: true
|
enable-accept-list: true
|
||||||
|
|
||||||
# 允许连接至服务的 ip 名单
|
# 允许连接至服务的 ip 名单
|
||||||
|
Reference in New Issue
Block a user