diff --git a/README.md b/README.md index d25e42b..fa71896 100644 --- a/README.md +++ b/README.md @@ -27,12 +27,10 @@ 为了适配 docker 环境,本插件除了从 `config.yml` 中配置服务器信息以外,还支持从环境变量中读取 -| 环境变量 | 描述 | 对应 config 值 | -|:----------------------------|:-------------------|:-----------------| -| BALL_LOCAL_SERVER_IP | 本服务器 IP | server-info.host | -| BALL_LOCAL_SERVER_PORT | 本服务器端口 | server-info.port | -| BALL_LOCAL_SERVER_INFO_ID | 本服务器唯一识别码,最长 32 字符 | server-info.id | -| BALL_LOCAL_SERVER_INFO_NAME | 本服务端名称,用于展示给玩家看 | server-info.name | +| 环境变量 | 描述 | 对应 config 值 | +|:-----------------|:-------------------|:-----------------| +| BALL_SERVER_ID | 本服务器唯一识别码,最长 32 字符 | server-info.id | +| BALL_SERVER_NAME | 本服务端名称,用于展示给玩家看 | server-info.name | # 开发 @@ -51,9 +49,9 @@ repositories { dependencies { // 对于 Bukkit 插件 - compileOnly("cn.hamster3.mc.plugin:ball-bukkit:1.5.7") + compileOnly("cn.hamster3.mc.plugin:ball-bukkit:1.6.0") // 对于 BungeeCord 插件 - compileOnly("cn.hamster3.mc.plugin:ball-bungee:1.5.7") + compileOnly("cn.hamster3.mc.plugin:ball-bungee:1.6.0") } ``` @@ -79,13 +77,13 @@ dependencies { cn.hamster3.mc.plugin ball-bukkit - 1.5.7 + 1.6.0 cn.hamster3.mc.plugin ball-bungee - 1.5.7 + 1.6.0 diff --git a/ball-bukkit/src/main/java/cn/hamster3/mc/plugin/ball/bukkit/api/BallBukkitAPI.java b/ball-bukkit/src/main/java/cn/hamster3/mc/plugin/ball/bukkit/api/BallBukkitAPI.java index 8b3e13b..8cc0bef 100644 --- a/ball-bukkit/src/main/java/cn/hamster3/mc/plugin/ball/bukkit/api/BallBukkitAPI.java +++ b/ball-bukkit/src/main/java/cn/hamster3/mc/plugin/ball/bukkit/api/BallBukkitAPI.java @@ -5,6 +5,7 @@ import cn.hamster3.mc.plugin.ball.common.api.BallAPI; import cn.hamster3.mc.plugin.ball.common.entity.BallServerType; import cn.hamster3.mc.plugin.core.common.config.ConfigSection; import cn.hamster3.mc.plugin.core.common.config.YamlConfig; +import org.bukkit.Bukkit; import org.jetbrains.annotations.NotNull; import java.io.File; @@ -31,6 +32,8 @@ public class BallBukkitAPI extends BallAPI { @Override public void enable() throws SQLException, InterruptedException { + instance.getLocalServerInfo().setHost(Bukkit.getIp().isEmpty() ? "127.0.0.1" : Bukkit.getIp()); + instance.getLocalServerInfo().setPort(Bukkit.getPort()); super.enable(); } diff --git a/ball-bungee/src/main/java/cn/hamster3/mc/plugin/ball/bungee/api/BallBungeeCordAPI.java b/ball-bungee/src/main/java/cn/hamster3/mc/plugin/ball/bungee/api/BallBungeeCordAPI.java index 4f5aafb..a7f8102 100644 --- a/ball-bungee/src/main/java/cn/hamster3/mc/plugin/ball/bungee/api/BallBungeeCordAPI.java +++ b/ball-bungee/src/main/java/cn/hamster3/mc/plugin/ball/bungee/api/BallBungeeCordAPI.java @@ -5,10 +5,13 @@ import cn.hamster3.mc.plugin.ball.common.api.BallAPI; import cn.hamster3.mc.plugin.ball.common.entity.BallServerType; import cn.hamster3.mc.plugin.core.common.config.ConfigSection; import cn.hamster3.mc.plugin.core.common.config.YamlConfig; +import net.md_5.bungee.api.ProxyServer; +import net.md_5.bungee.api.config.ListenerInfo; import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; +import java.net.InetSocketAddress; import java.sql.SQLException; import java.util.logging.Logger; @@ -31,6 +34,14 @@ public class BallBungeeCordAPI extends BallAPI { @Override public void enable() throws SQLException, InterruptedException { + for (ListenerInfo listenerInfo : ProxyServer.getInstance().getConfig().getListeners()) { + if (!(listenerInfo.getSocketAddress() instanceof InetSocketAddress)) { + continue; + } + InetSocketAddress address = (InetSocketAddress) listenerInfo.getSocketAddress(); + instance.getLocalServerInfo().setHost(address.getHostString()); + instance.getLocalServerInfo().setPort(address.getPort()); + } super.enable(); } diff --git a/ball-common/src/main/java/cn/hamster3/mc/plugin/ball/common/api/BallAPI.java b/ball-common/src/main/java/cn/hamster3/mc/plugin/ball/common/api/BallAPI.java index af9e218..1985911 100644 --- a/ball-common/src/main/java/cn/hamster3/mc/plugin/ball/common/api/BallAPI.java +++ b/ball-common/src/main/java/cn/hamster3/mc/plugin/ball/common/api/BallAPI.java @@ -13,6 +13,7 @@ import cn.hamster3.mc.plugin.ball.common.event.server.ServerOfflineEvent; import cn.hamster3.mc.plugin.ball.common.listener.BallCommonListener; import cn.hamster3.mc.plugin.ball.common.listener.BallDebugListener; import cn.hamster3.mc.plugin.ball.common.listener.BallRedisListener; +import cn.hamster3.mc.plugin.ball.common.thread.LockUpdateThread; import cn.hamster3.mc.plugin.core.common.api.CoreAPI; import cn.hamster3.mc.plugin.core.common.config.ConfigSection; import cn.hamster3.mc.plugin.core.common.data.DisplayMessage; @@ -29,6 +30,8 @@ import javax.sql.DataSource; import java.sql.*; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; @Getter @@ -66,8 +69,8 @@ public abstract class BallAPI { @NotNull private final Jedis redisSub; - @NotNull - private final Jedis redisPub; + @Nullable + private ScheduledFuture lockUpdater; public BallAPI(@NotNull ConfigSection config, BallServerType type) { ConfigSection serverInfoConfig = config.getSection("server-info"); @@ -89,7 +92,6 @@ public abstract class BallAPI { allServerInfo = new ConcurrentHashMap<>(); allPlayerInfo = new ConcurrentHashMap<>(); redisSub = CoreAPI.getInstance().getJedisPool().getResource(); - redisPub = CoreAPI.getInstance().getJedisPool().getResource(); getLogger().info("频道前缀: " + ballConfig.getChannelPrefix()); getLogger().info("启用子服更新玩家状态: " + ballConfig.isGameServerUpdatePlayerInfo()); if (ballConfig.isGameServerUpdatePlayerInfo()) { @@ -102,6 +104,29 @@ public abstract class BallAPI { } protected void enable() throws SQLException, InterruptedException { + try (Jedis jedis = CoreAPI.getInstance().getJedisPool().getResource()) { + String key = "HamsterBall:ServerInfo:" + localServerInfo.getId(); + if (jedis.exists(key)) { + throw new IllegalStateException("已经有一个服务器占用了该 ID"); + } + jedis.hset(key, "id", localServerInfo.getId()); + jedis.hset(key, "name", localServerInfo.getName()); + jedis.hset(key, "type", localServerInfo.getType().name()); + jedis.hset(key, "host", localServerInfo.getHost()); + jedis.hset(key, "port", String.valueOf(localServerInfo.getPort())); + jedis.expire(key, 180); + lockUpdater = CoreAPI.getInstance().getScheduledService().scheduleAtFixedRate(LockUpdateThread.INSTANCE, 1, 1, TimeUnit.MINUTES); + for (String serverInfoKey : jedis.keys("HamsterBall:ServerInfo:*")) { + BallServerInfo info = new BallServerInfo( + jedis.hget(serverInfoKey, "id"), + jedis.hget(serverInfoKey, "name"), + BallServerType.valueOf(jedis.hget(serverInfoKey, "type")), + jedis.hget(serverInfoKey, "host"), + Integer.parseInt(jedis.hget(serverInfoKey, "port")) + ); + allServerInfo.put(info.getId(), info); + } + } try (Connection connection = getDatasource().getConnection()) { try (Statement statement = connection.createStatement()) { statement.execute("CREATE TABLE IF NOT EXISTS `hamster_ball_player_info`(" + @@ -111,44 +136,11 @@ public abstract class BallAPI { "`proxy_server` VARCHAR(32) NOT NULL," + "`online` BOOLEAN NOT NULL" + ") CHARSET utf8mb4;"); - statement.execute("CREATE TABLE IF NOT EXISTS `hamster_ball_server_info`(" + - "`id` VARCHAR(32) PRIMARY KEY NOT NULL," + - "`name` VARCHAR(32) NOT NULL," + - "`type` VARCHAR(16) NOT NULL," + - "`host` VARCHAR(32) NOT NULL," + - "`port` INT NOT NULL" + - ") CHARSET utf8mb4;"); statement.execute("CREATE TABLE IF NOT EXISTS `hamster_ball_cached_message`(" + "`uuid` CHAR(36) NOT NULL," + "`message` TEXT NOT NULL" + ") CHARSET utf8mb4;"); } - try (PreparedStatement statement = connection.prepareStatement( - "REPLACE INTO `hamster_ball_server_info` VALUES(?, ?, ?, ?, ?);" - )) { - statement.setString(1, localServerInfo.getId()); - statement.setString(2, localServerInfo.getName()); - statement.setString(3, localServerInfo.getType().name()); - statement.setString(4, localServerInfo.getHost()); - statement.setInt(5, localServerInfo.getPort()); - statement.executeUpdate(); - } - try (PreparedStatement statement = connection.prepareStatement( - "SELECT * FROM `hamster_ball_server_info`;" - )) { - try (ResultSet set = statement.executeQuery()) { - while (set.next()) { - String serverID = set.getString("id"); - allServerInfo.put(serverID, new BallServerInfo( - serverID, - set.getString("name"), - BallServerType.valueOf(set.getString("type")), - set.getString("host"), - set.getInt("port") - )); - } - } - } if (getBallConfig().isGameServerUpdatePlayerInfo()) { try (Statement statement = connection.createStatement()) { try (ResultSet set = statement.executeQuery(String.format( @@ -193,14 +185,15 @@ public abstract class BallAPI { sendBallMessage(BallAPI.BALL_CHANNEL, new BallMessage( BallActions.ServerOffline.name(), new ServerOfflineEvent(getLocalServerInfo()) ), false, true); - - try (Connection connection = getDatasource().getConnection()) { - try (PreparedStatement statement = connection.prepareStatement( - "DELETE FROM `hamster_ball_server_info` WHERE `id`=?;" - )) { - statement.setString(1, getLocalServerId()); - statement.executeUpdate(); + if (lockUpdater != null) { + lockUpdater.cancel(true); + lockUpdater = null; + try (Jedis jedis = CoreAPI.getInstance().getJedisPool().getResource()) { + String key = "HamsterBall:ServerInfo:" + localServerInfo.getId(); + jedis.del(key); } + } + try (Connection connection = getDatasource().getConnection()) { try (PreparedStatement statement = connection.prepareStatement( "UPDATE `hamster_ball_player_info` SET `online`=false WHERE `game_server`=? OR `proxy_server`=?" )) { @@ -210,7 +203,6 @@ public abstract class BallAPI { } } redisSub.close(); - redisPub.close(); } /** @@ -493,12 +485,17 @@ public abstract class BallAPI { channel = ballConfig.getChannelPrefix() + channel; } if (block) { - redisPub.publish(channel, CoreAPI.getInstance().getGson().toJson(message)); + try (Jedis jedis = CoreAPI.getInstance().getJedisPool().getResource()) { + jedis.publish(channel, CoreAPI.getInstance().getGson().toJson(message)); + } eventBus.post(new MessageSentEvent(channel, message)); } else { @NotNull String finalChannel = channel; CoreAPI.getInstance().getExecutorService().submit(() -> { - redisPub.publish(finalChannel, CoreAPI.getInstance().getGson().toJson(message)); + try (Jedis jedis = CoreAPI.getInstance().getJedisPool().getResource()) { + jedis.publish(finalChannel, CoreAPI.getInstance().getGson().toJson(message)); + } + eventBus.post(new MessageSentEvent(finalChannel, message)); }); } } diff --git a/ball-common/src/main/java/cn/hamster3/mc/plugin/ball/common/entity/BallServerInfo.java b/ball-common/src/main/java/cn/hamster3/mc/plugin/ball/common/entity/BallServerInfo.java index d9f49ad..5490d2f 100644 --- a/ball-common/src/main/java/cn/hamster3/mc/plugin/ball/common/entity/BallServerInfo.java +++ b/ball-common/src/main/java/cn/hamster3/mc/plugin/ball/common/entity/BallServerInfo.java @@ -45,13 +45,11 @@ public class BallServerInfo { public BallServerInfo(@NotNull ConfigSection config, BallServerType type) { Map env = System.getenv(); - id = env.getOrDefault("BALL_LOCAL_SERVER_INFO_ID", config.getString("id")); - name = env.getOrDefault("BALL_LOCAL_SERVER_INFO_NAME", config.getString("name")); + id = env.getOrDefault("BALL_SERVER_ID", config.getString("id")); + name = env.getOrDefault("BALL_SERVER_NAME", config.getString("name")); this.type = type; - host = env.getOrDefault("BALL_LOCAL_SERVER_IP", config.getString("host")); - port = Integer.parseInt( - env.getOrDefault("BALL_LOCAL_SERVER_PORT", String.valueOf(config.getInt("port"))) - ); + host = "0.0.0.0"; + port = 0; } @Override diff --git a/ball-common/src/main/java/cn/hamster3/mc/plugin/ball/common/thread/LockUpdateThread.java b/ball-common/src/main/java/cn/hamster3/mc/plugin/ball/common/thread/LockUpdateThread.java new file mode 100644 index 0000000..2c7b147 --- /dev/null +++ b/ball-common/src/main/java/cn/hamster3/mc/plugin/ball/common/thread/LockUpdateThread.java @@ -0,0 +1,20 @@ +package cn.hamster3.mc.plugin.ball.common.thread; + +import cn.hamster3.mc.plugin.ball.common.api.BallAPI; +import cn.hamster3.mc.plugin.core.common.api.CoreAPI; +import cn.hamster3.mc.plugin.core.lib.redis.clients.jedis.Jedis; + +public class LockUpdateThread implements Runnable { + public static final LockUpdateThread INSTANCE = new LockUpdateThread(); + + private LockUpdateThread() { + } + + @Override + public void run() { + String key = "HamsterBall:ServerInfo:" + BallAPI.getInstance().getLocalServerInfo().getId(); + try (Jedis jedis = CoreAPI.getInstance().getJedisPool().getResource()) { + jedis.expire(key, 180); + } + } +}