diff --git a/ball-velocity/build.gradle.kts b/ball-velocity/build.gradle.kts new file mode 100644 index 0000000..b1f2d47 --- /dev/null +++ b/ball-velocity/build.gradle.kts @@ -0,0 +1,41 @@ +@file:Suppress("VulnerableLibrariesLocal") + +evaluationDependsOn(":ball-common") + +dependencies { + api(project(":ball-common")) { isTransitive = false } + compileOnly("com.velocitypowered:velocity-api:3.3.0-SNAPSHOT") + annotationProcessor("com.velocitypowered:velocity-api:3.3.0-SNAPSHOT") + compileOnly("cn.hamster3.mc.plugin:core-common:+") +} + +sourceSets.create("templates") { + java { + srcDir("src/main/templates") + } +} + +val templateSource = file("src/main/templates") +val templateDest = layout.buildDirectory.dir("generated/sources/templates") +val generateTemplates = tasks.register("generateTemplates") { + from(templateSource) + into(templateDest) + expand(project.properties) +} + +sourceSets.main.get().java.srcDir(generateTemplates.map { it.outputs }) + +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + withSourcesJar() +} + +tasks { + withType { + archiveBaseName = "HamsterBall-Velocity" + } + shadowJar { + destinationDirectory = rootProject.layout.buildDirectory + } +} diff --git a/ball-velocity/src/main/java/cn/hamster3/mc/plugin/ball/velocity/HamsterBallPlugin.java b/ball-velocity/src/main/java/cn/hamster3/mc/plugin/ball/velocity/HamsterBallPlugin.java new file mode 100644 index 0000000..716e38c --- /dev/null +++ b/ball-velocity/src/main/java/cn/hamster3/mc/plugin/ball/velocity/HamsterBallPlugin.java @@ -0,0 +1,139 @@ +package cn.hamster3.mc.plugin.ball.velocity; + +import cn.hamster3.mc.plugin.ball.common.api.BallAPI; +import cn.hamster3.mc.plugin.ball.common.entity.BallPlayerInfo; +import cn.hamster3.mc.plugin.ball.common.event.BallActions; +import cn.hamster3.mc.plugin.ball.common.event.server.ServerOnlineEvent; +import cn.hamster3.mc.plugin.ball.velocity.api.CoreVelocityAPI; +import cn.hamster3.mc.plugin.ball.velocity.listener.BallVelocityListener; +import cn.hamster3.mc.plugin.ball.velocity.listener.BallVelocityMainListener; +import cn.hamster3.mc.plugin.ball.velocity.listener.UpdatePlayerInfoListener; +import cn.hamster3.mc.plugin.ball.velocity.util.BallVelocityUtils; +import com.google.inject.Inject; +import com.velocitypowered.api.event.PostOrder; +import com.velocitypowered.api.event.Subscribe; +import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; +import com.velocitypowered.api.event.proxy.ProxyShutdownEvent; +import com.velocitypowered.api.plugin.Dependency; +import com.velocitypowered.api.plugin.Plugin; +import com.velocitypowered.api.plugin.annotation.DataDirectory; +import com.velocitypowered.api.proxy.ProxyServer; +import lombok.Getter; +import net.kyori.adventure.text.Component; +import org.slf4j.Logger; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.Objects; +import java.util.logging.Level; + +@Plugin( + id = "hamster-ball", + name = "HamsterBall", + version = BuildConstants.VERSION, + description = BuildConstants.DESCRIPTION, + authors = {"MiniDay"}, + dependencies = @Dependency(id = "hamster-core") +) +public class HamsterBallPlugin { + @Getter + private static HamsterBallPlugin instance; + @Getter + private final java.util.logging.Logger logger; + @Getter + private final Logger slf4jLogger; + @Getter + private final ProxyServer proxyServer; + @Getter + private final File dataFolder; + + @Inject + public HamsterBallPlugin(Logger slf4jLogger, ProxyServer proxyServer, @DataDirectory Path dataPath) { + long start = System.currentTimeMillis(); + logger = java.util.logging.Logger.getLogger("hamster-ball"); + this.slf4jLogger = slf4jLogger; + this.proxyServer = proxyServer; + dataFolder = dataPath.toFile(); + logger.info("仓鼠球正在初始化"); + instance = this; + try { + File dataFolder = getDataFolder(); + if (dataFolder.mkdir()) { + logger.info("已生成插件存档文件夹"); + } + File configFile = new File(dataFolder, "config.yml"); + if (!configFile.exists()) { + Files.copy( + Objects.requireNonNull(getClass().getResourceAsStream("/config.yml")), + configFile.toPath(), + StandardCopyOption.REPLACE_EXISTING + ); + } + CoreVelocityAPI.init(configFile); + logger.info("已初始化 BallAPI"); + } catch (Exception e) { + slf4jLogger.error("BallAPI 初始化失败", e); + proxyServer.shutdown(Component.text("由于 HamsterBall 初始化失败, 服务器将立即关闭")); + } + long time = System.currentTimeMillis() - start; + logger.info("仓鼠球初始化完成,总计耗时 " + time + " ms"); + } + + @Subscribe(order = PostOrder.EARLY) + public void onProxyInitialization(ProxyInitializeEvent event) { + long start = System.currentTimeMillis(); + java.util.logging.Logger logger = getLogger(); + logger.info("仓鼠球正在启动"); + try { + CoreVelocityAPI.getInstance().enable(); + } catch (Exception e) { + logger.log(Level.SEVERE, "仓鼠球启动失败", e); + logger.info("由于仓鼠球启动失败,服务器将立即关闭"); + proxyServer.shutdown(Component.text("仓鼠球启动失败")); + return; + } + BallAPI.getInstance().getEventBus().register(BallVelocityListener.INSTANCE); + logger.info("已注册监听器 BallBungeeListener"); + proxyServer.getEventManager().register(this, BallVelocityMainListener.INSTANCE); + logger.info("已注册监听器 BallBungeeMainListener"); + proxyServer.getEventManager().register(this, UpdatePlayerInfoListener.INSTANCE); + logger.info("已注册监听器 UpdatePlayerInfoListener"); + + if (BallAPI.getInstance().getBallConfig().isGameServerUpdatePlayerInfo()) { + BallAPI.getInstance().subscribePatterns("*" + BallAPI.PLAYER_INFO_CHANNEL); + } else { + BallAPI.getInstance().subscribeIgnorePrefix(BallAPI.PLAYER_INFO_CHANNEL); + } + BallAPI.getInstance().sendRawBallMessage( + BallAPI.BALL_CHANNEL, BallActions.ServerOnline.name(), + new ServerOnlineEvent(BallAPI.getInstance().getLocalServerInfo()) + ); + // 移除失效的在线玩家 + BallAPI.getInstance().getAllPlayerInfo().values() + .stream() + .filter(BallPlayerInfo::isOnline) + .filter(o -> BallAPI.getInstance().isLocalServer(o.getProxyServer())) + .forEach(playerInfo -> { + playerInfo.setOnline(false); + BallVelocityUtils.uploadPlayerInfo(playerInfo); + }); + long time = System.currentTimeMillis() - start; + logger.info("仓鼠球启动完成,总计耗时 " + time + " ms"); + } + + @Subscribe(order = PostOrder.LATE) + public void onProxyShutdown(ProxyShutdownEvent event) { + long start = System.currentTimeMillis(); + java.util.logging.Logger logger = getLogger(); + logger.info("仓鼠球正在关闭"); + try { + CoreVelocityAPI.getInstance().disable(); + } catch (Exception e) { + logger.log(Level.SEVERE, "关闭仓鼠球时遇到了一个异常", e); + } + long time = System.currentTimeMillis() - start; + logger.info("仓鼠球已关闭,总计耗时 " + time + " ms"); + } +} \ No newline at end of file diff --git a/ball-velocity/src/main/java/cn/hamster3/mc/plugin/ball/velocity/api/CoreVelocityAPI.java b/ball-velocity/src/main/java/cn/hamster3/mc/plugin/ball/velocity/api/CoreVelocityAPI.java new file mode 100644 index 0000000..2b72dfe --- /dev/null +++ b/ball-velocity/src/main/java/cn/hamster3/mc/plugin/ball/velocity/api/CoreVelocityAPI.java @@ -0,0 +1,61 @@ +package cn.hamster3.mc.plugin.ball.velocity.api; + +import cn.hamster3.mc.plugin.ball.common.api.BallAPI; +import cn.hamster3.mc.plugin.ball.common.entity.BallServerType; +import cn.hamster3.mc.plugin.ball.velocity.HamsterBallPlugin; +import cn.hamster3.mc.plugin.core.common.config.ConfigSection; +import cn.hamster3.mc.plugin.core.common.config.YamlConfig; +import com.velocitypowered.api.proxy.config.ProxyConfig; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.sql.SQLException; +import java.util.logging.Logger; + +@SuppressWarnings("unused") +public final class CoreVelocityAPI extends BallAPI { + public CoreVelocityAPI(@NotNull ConfigSection config) { + super(config, BallServerType.PROXY); + } + + public static CoreVelocityAPI getInstance() { + return (CoreVelocityAPI) instance; + } + + public static void init(@NotNull File configFile) throws IOException { + if (instance != null) { + return; + } + YamlConfig config = YamlConfig.load(configFile); + instance = new CoreVelocityAPI(config); + } + + @Override + public void enable() throws SQLException, InterruptedException { + ProxyConfig config = HamsterBallPlugin.getInstance().getProxyServer().getConfiguration(); + try { + Field field = config.getClass().getDeclaredField("bind"); + field.setAccessible(true); + String bind = (String) field.get(config); + int i = bind.lastIndexOf(":"); + String substring = bind.substring(i + 1); + instance.getLocalServerInfo().setHost(bind.substring(0, i)); + instance.getLocalServerInfo().setPort(Integer.parseInt(substring)); + } catch (Exception e) { + HamsterBallPlugin.getInstance().getSlf4jLogger().error("获取 Velocity 监听端口时遇到了一个异常", e); + } + super.enable(); + } + + @Override + public void disable() throws SQLException, InterruptedException { + super.disable(); + } + + @Override + public @NotNull Logger getLogger() { + return HamsterBallPlugin.getInstance().getLogger(); + } +} diff --git a/ball-velocity/src/main/java/cn/hamster3/mc/plugin/ball/velocity/listener/BallVelocityListener.java b/ball-velocity/src/main/java/cn/hamster3/mc/plugin/ball/velocity/listener/BallVelocityListener.java new file mode 100644 index 0000000..284e0ff --- /dev/null +++ b/ball-velocity/src/main/java/cn/hamster3/mc/plugin/ball/velocity/listener/BallVelocityListener.java @@ -0,0 +1,121 @@ +package cn.hamster3.mc.plugin.ball.velocity.listener; + +import cn.hamster3.mc.plugin.ball.common.api.BallAPI; +import cn.hamster3.mc.plugin.ball.common.entity.BallServerType; +import cn.hamster3.mc.plugin.ball.common.event.operate.*; +import cn.hamster3.mc.plugin.ball.velocity.HamsterBallPlugin; +import cn.hamster3.mc.plugin.core.common.api.CoreAPI; +import com.google.common.eventbus.Subscribe; +import com.velocitypowered.api.proxy.Player; +import com.velocitypowered.api.proxy.ProxyServer; +import com.velocitypowered.api.proxy.ServerConnection; +import com.velocitypowered.api.proxy.server.RegisteredServer; +import com.velocitypowered.api.proxy.server.ServerInfo; +import net.kyori.adventure.audience.Audience; + +import java.util.UUID; + +public class BallVelocityListener { + public static final BallVelocityListener INSTANCE = new BallVelocityListener(); + + private BallVelocityListener() { + } + + @Subscribe + public void onDispatchConsoleCommand(DispatchConsoleCommandEvent event) { + if (event.getType() != null && event.getType() != BallServerType.PROXY) { + return; + } + if (event.getServerID() != null && !BallAPI.getInstance().isLocalServer(event.getServerID())) { + return; + } + ProxyServer server = HamsterBallPlugin.getInstance().getProxyServer(); + server.getCommandManager().executeAsync(server.getConsoleCommandSource(), event.getCommand()); + } + + @Subscribe + public void onDispatchPlayerCommand(DispatchPlayerCommandEvent event) { + if (event.getType() != null && event.getType() != BallServerType.GAME) { + return; + } + ProxyServer server = HamsterBallPlugin.getInstance().getProxyServer(); + if (event.getUuid() != null) { + Player player = server.getPlayer(event.getUuid()).orElse(null); + if (player == null) { + return; + } + server.getCommandManager().executeAsync(player, event.getCommand()); + return; + } + for (Player player : server.getAllPlayers()) { + server.getCommandManager().executeAsync(player, event.getCommand()); + } + } + + @Subscribe + public void onKickPlayer(KickPlayerEvent event) { + ProxyServer server = HamsterBallPlugin.getInstance().getProxyServer(); + Player player = server.getPlayer(event.getUuid()).orElse(null); + if (player == null) { + return; + } + player.disconnect(event.getReason()); + } + + @Subscribe + public void onSendMessageToPlayer(SendMessageToPlayerEvent event) { + for (UUID receiver : event.getReceivers()) { + Audience audience = CoreAPI.getInstance().getAudienceProvider().player(receiver); + event.getMessage().show(audience); + } + } + + @Subscribe + public void onSendPlayerToLocation(SendPlayerToLocationEvent event) { + ProxyServer proxyServer = HamsterBallPlugin.getInstance().getProxyServer(); + String serverID = event.getLocation().getServerID(); + RegisteredServer toServer = proxyServer.getServer(serverID).orElse(null); + if (toServer == null) { + HamsterBallPlugin.getInstance().getLogger().warning("试图传送玩家时失败: 服务器 " + serverID + " 不在线"); + return; + } + for (UUID uuid : event.getSendPlayerUUID()) { + Player player = proxyServer.getPlayer(uuid).orElse(null); + if (player == null) { + continue; + } + RegisteredServer currentServer = player.getCurrentServer().map(ServerConnection::getServer).orElse(null); + if (currentServer != null && currentServer.getServerInfo().getName().equals(serverID)) { + continue; + } + player.createConnectionRequest(toServer).fireAndForget(); + } + } + + @Subscribe + public void onSendPlayerToPlayer(SendPlayerToPlayerEvent event) { + ProxyServer proxyServer = HamsterBallPlugin.getInstance().getProxyServer(); + UUID toPlayerUUID = event.getToPlayerUUID(); + Player toPlayer = proxyServer.getPlayer(toPlayerUUID).orElse(null); + if (toPlayer == null) { + HamsterBallPlugin.getInstance().getLogger().warning("试图传送玩家时失败: 目标玩家 " + toPlayerUUID + " 不在线"); + return; + } + RegisteredServer toServer = toPlayer.getCurrentServer().map(ServerConnection::getServer).orElse(null); + if (toServer == null) { + HamsterBallPlugin.getInstance().getLogger().warning("试图传送玩家时失败: 目标玩家 " + toPlayerUUID + " 不在任何服务器中"); + return; + } + for (UUID uuid : event.getSendPlayerUUID()) { + Player sendPlayer = proxyServer.getPlayer(uuid).orElse(null); + if (sendPlayer == null) { + continue; + } + ServerInfo currentServer = sendPlayer.getCurrentServer().map(ServerConnection::getServerInfo).orElse(null); + if (currentServer != null && currentServer.getName().equals(toServer.getServerInfo().getName())) { + continue; + } + sendPlayer.createConnectionRequest(toServer).fireAndForget(); + } + } +} diff --git a/ball-velocity/src/main/java/cn/hamster3/mc/plugin/ball/velocity/listener/BallVelocityMainListener.java b/ball-velocity/src/main/java/cn/hamster3/mc/plugin/ball/velocity/listener/BallVelocityMainListener.java new file mode 100644 index 0000000..6b2cbf2 --- /dev/null +++ b/ball-velocity/src/main/java/cn/hamster3/mc/plugin/ball/velocity/listener/BallVelocityMainListener.java @@ -0,0 +1,58 @@ +package cn.hamster3.mc.plugin.ball.velocity.listener; + +import cn.hamster3.mc.plugin.ball.common.api.BallAPI; +import cn.hamster3.mc.plugin.ball.common.entity.BallPlayerInfo; +import cn.hamster3.mc.plugin.ball.common.event.BallActions; +import cn.hamster3.mc.plugin.ball.common.event.player.BallPlayerLoginEvent; +import cn.hamster3.mc.plugin.ball.common.event.player.BallPlayerPostLoginEvent; +import cn.hamster3.mc.plugin.ball.common.event.player.BallPlayerPreLoginEvent; +import cn.hamster3.mc.plugin.ball.velocity.util.BallVelocityUtils; +import com.velocitypowered.api.event.PostOrder; +import com.velocitypowered.api.event.Subscribe; +import com.velocitypowered.api.event.connection.LoginEvent; +import com.velocitypowered.api.event.connection.PostLoginEvent; +import com.velocitypowered.api.event.connection.PreLoginEvent; +import com.velocitypowered.api.proxy.Player; + +public final class BallVelocityMainListener { + public static final BallVelocityMainListener INSTANCE = new BallVelocityMainListener(); + + private BallVelocityMainListener() { + } + + @Subscribe(order = PostOrder.LATE) + public void onPreLogin(PreLoginEvent event) { + BallAPI.getInstance().sendRawBallMessage( + BallAPI.BALL_CHANNEL, + BallActions.BallPlayerPreLogin.name(), + new BallPlayerPreLoginEvent(event.getUsername()) + ); + } + + @Subscribe(order = PostOrder.LATE) + public void onLogin(LoginEvent event) { + if (!event.getResult().isAllowed()) { + return; + } + Player player = event.getPlayer(); + BallAPI.getInstance().sendRawBallMessage( + BallAPI.BALL_CHANNEL, + BallActions.BallPlayerLogin.name(), + new BallPlayerLoginEvent(new BallPlayerInfo( + player.getUniqueId(), player.getUsername(), "connecting", + BallAPI.getInstance().getLocalServerId(), true + )) + ); + } + + @Subscribe(order = PostOrder.LATE) + public void onPostLogin(PostLoginEvent event) { + Player player = event.getPlayer(); + BallPlayerInfo playerInfo = BallVelocityUtils.getPlayerInfo(player, true); + BallAPI.getInstance().sendRawBallMessage( + BallAPI.BALL_CHANNEL, + BallActions.BallPlayerPostLogin.name(), + new BallPlayerPostLoginEvent(playerInfo) + ); + } +} diff --git a/ball-velocity/src/main/java/cn/hamster3/mc/plugin/ball/velocity/listener/UpdatePlayerInfoListener.java b/ball-velocity/src/main/java/cn/hamster3/mc/plugin/ball/velocity/listener/UpdatePlayerInfoListener.java new file mode 100644 index 0000000..af536f5 --- /dev/null +++ b/ball-velocity/src/main/java/cn/hamster3/mc/plugin/ball/velocity/listener/UpdatePlayerInfoListener.java @@ -0,0 +1,67 @@ +package cn.hamster3.mc.plugin.ball.velocity.listener; + +import cn.hamster3.mc.plugin.ball.common.api.BallAPI; +import cn.hamster3.mc.plugin.ball.common.entity.BallPlayerInfo; +import cn.hamster3.mc.plugin.ball.common.event.BallActions; +import cn.hamster3.mc.plugin.ball.common.event.player.BallPlayerLogoutEvent; +import cn.hamster3.mc.plugin.ball.common.event.player.BallPlayerPostConnectServerEvent; +import cn.hamster3.mc.plugin.ball.common.event.player.BallPlayerPreConnectServerEvent; +import cn.hamster3.mc.plugin.ball.velocity.util.BallVelocityUtils; +import com.velocitypowered.api.event.PostOrder; +import com.velocitypowered.api.event.Subscribe; +import com.velocitypowered.api.event.connection.DisconnectEvent; +import com.velocitypowered.api.event.player.ServerPostConnectEvent; +import com.velocitypowered.api.event.player.ServerPreConnectEvent; +import com.velocitypowered.api.proxy.Player; + +public class UpdatePlayerInfoListener { + public static final UpdatePlayerInfoListener INSTANCE = new UpdatePlayerInfoListener(); + + private UpdatePlayerInfoListener() { + } + + @Subscribe(order = PostOrder.LATE) + public void onServerConnect(ServerPreConnectEvent event) { + if (event.getResult().isAllowed()) { + return; + } + String name = event.getResult().getServer() + .map(o -> o.getServerInfo().getName()) + .orElse(event.getOriginalServer().getServerInfo().getName()); + Player player = event.getPlayer(); + BallPlayerInfo playerInfo = BallVelocityUtils.getPlayerInfo(player, true); + playerInfo.setGameServer(name); + BallAPI.getInstance().sendRawBallMessage( + BallAPI.BALL_CHANNEL, + BallActions.BallPlayerPreConnectServer.name(), + new BallPlayerPreConnectServerEvent(playerInfo, playerInfo.getGameServer(), name) + ); + BallVelocityUtils.uploadPlayerInfo(playerInfo); + } + + @SuppressWarnings("UnstableApiUsage") + @Subscribe(order = PostOrder.LATE) + public void onServerPostConnect(ServerPostConnectEvent event) { + Player player = event.getPlayer(); + BallPlayerInfo playerInfo = BallVelocityUtils.getPlayerInfo(player, true); + playerInfo.setGameServer(player.getCurrentServer().map(o -> o.getServerInfo().getName()).orElse("")); + BallAPI.getInstance().sendRawBallMessage( + BallAPI.BALL_CHANNEL, + BallActions.BallPlayerPostConnectServer.name(), + new BallPlayerPostConnectServerEvent(playerInfo) + ); + BallVelocityUtils.uploadPlayerInfo(playerInfo); + } + + @Subscribe(order = PostOrder.LATE) + public void onDisconnect(DisconnectEvent event) { + Player player = event.getPlayer(); + BallPlayerInfo playerInfo = BallVelocityUtils.getPlayerInfo(player, false); + BallAPI.getInstance().sendRawBallMessage( + BallAPI.BALL_CHANNEL, + BallActions.BallPlayerLogout.name(), + new BallPlayerLogoutEvent(playerInfo) + ); + BallVelocityUtils.uploadPlayerInfo(playerInfo); + } +} diff --git a/ball-velocity/src/main/java/cn/hamster3/mc/plugin/ball/velocity/util/BallVelocityUtils.java b/ball-velocity/src/main/java/cn/hamster3/mc/plugin/ball/velocity/util/BallVelocityUtils.java new file mode 100644 index 0000000..24e921d --- /dev/null +++ b/ball-velocity/src/main/java/cn/hamster3/mc/plugin/ball/velocity/util/BallVelocityUtils.java @@ -0,0 +1,58 @@ +package cn.hamster3.mc.plugin.ball.velocity.util; + +import cn.hamster3.mc.plugin.ball.common.api.BallAPI; +import cn.hamster3.mc.plugin.ball.common.entity.BallPlayerInfo; +import cn.hamster3.mc.plugin.ball.common.event.BallActions; +import cn.hamster3.mc.plugin.ball.common.event.player.BallPlayerInfoUpdateEvent; +import cn.hamster3.mc.plugin.core.common.api.CoreAPI; +import com.velocitypowered.api.proxy.Player; +import com.velocitypowered.api.proxy.ServerConnection; +import org.jetbrains.annotations.NotNull; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.logging.Level; + +public final class BallVelocityUtils { + private BallVelocityUtils() { + } + + @NotNull + public static BallPlayerInfo getPlayerInfo(@NotNull Player player, boolean online) { + ServerConnection server = player.getCurrentServer().orElse(null); + return new BallPlayerInfo( + player.getUniqueId(), + player.getUsername(), + server == null ? "connecting" : server.getServerInfo().getName(), + BallAPI.getInstance().getLocalServerId(), + online + ); + } + + public static void uploadPlayerInfo(@NotNull BallPlayerInfo playerInfo) { + CoreAPI.getInstance().getExecutorService().execute(() -> { + try (Connection connection = BallAPI.getInstance().getDatasource().getConnection()) { + try (PreparedStatement statement = connection.prepareStatement( + "REPLACE INTO `hamster_ball_player_info` VALUES(?, ?, ?, ?, ?);" + )) { + statement.setString(1, playerInfo.getUuid().toString()); + statement.setString(2, playerInfo.getName()); + statement.setString(3, playerInfo.getGameServer()); + statement.setString(4, playerInfo.getProxyServer()); + statement.setBoolean(5, playerInfo.isOnline()); + statement.executeUpdate(); + } + } catch (SQLException e) { + BallAPI.getInstance().getLogger().log(Level.SEVERE, "更新玩家数据时遇到了一个异常", e); + } + if (!BallAPI.getInstance().getBallConfig().isGameServerUpdatePlayerInfo()) { + BallAPI.getInstance().sendRawBallMessage( + BallAPI.PLAYER_INFO_CHANNEL, + BallActions.BallPlayerInfoUpdate.name(), + new BallPlayerInfoUpdateEvent(playerInfo) + ); + } + }); + } +} diff --git a/ball-velocity/src/main/resources/config.yml b/ball-velocity/src/main/resources/config.yml new file mode 100644 index 0000000..f5d5f93 --- /dev/null +++ b/ball-velocity/src/main/resources/config.yml @@ -0,0 +1,66 @@ +# 是否允许在控制台输出调试信息 +debug: false + +# 频道名前缀 +# 使用这个配置选项可以划分子服消息通信分组 +# 只有在同一个频道名的子服才能互相通信 +channel-prefix: "" + +# 是否在子服端更新玩家信息 +# 默认情况下,BC 统一管理玩家信息,包括记录 UUID 和玩家名称 +# 如果一个群组服同时拥有多个 BC 入口 +# 且每个 BC 入口为不同的玩家名称分配不同的 UUID +# (例如正版、盗版双入口,或网易多入口接同一个子服) +# 则可以启用该功能以防止 UUID 紊乱的问题 +game-server-update-player-info: false + +# 本服务器信息 +server-info: + # 服务器唯一识别码,最长 32 字符 + id: "Velocity" + # 服务端名称,常用于展示给玩家看 + name: "代理端" + # 当前子服的地址 + # 不填则自动设置为 0.0.0.0 + host: 0.0.0.0 + # 当前子服端口 + # 不填则自动设置为 25577 + port: 25577 + +# 数据库连接池配置 +# 如果注释该选项则默认使用 HamsterCore 中的连接池配置 +# 否则 HamsterBall 将会使用与 HamsterCore 不同的数据库链接 +# 如果你需要让每个服务器单独存储仓鼠球信息 +# 这个选项就会很有用 +#datasource: +# # 数据库链接驱动地址 +# driver: "com.mysql.jdbc.Driver" +# # 数据库链接填写格式: +# # jdbc:mysql://{数据库地址}:{数据库端口}/{使用的库名}?参数 +# # 除非你知道自己在做什么,否则不建议随意更改参数 +# url: "jdbc:mysql://localhost:3306/Test1?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true" +# # 用户名 +# username: "Test" +# # 密码 +# password: "Test123.." +# # 最小闲置链接数 +# # 推荐值:1~3 +# minimum-idle: 0 +# # 最大链接数 +# # 推荐值:不低于3 +# maximum-pool-size: 3 +# # 保持连接池可用的间隔 +# # 除非你的服务器数据库连接经常断开,否则不建议启用该选项 +# # 单位:毫秒 +# # 默认值为0(禁用) +# keep-alive-time: 0 +# # 连接闲置回收时间 +# # 单位:毫秒 +# # 推荐值:600000(10分钟) +# idle-timeout: 600000 +# # 链接最长存活时间 +# # 单位:毫秒 +# max-lifetime: 1800000 +# # 验证连接存活的超时时间 +# # 单位:毫秒 +# validation-timeout: 5000 diff --git a/ball-velocity/src/main/resources/jenkins.yml b/ball-velocity/src/main/resources/jenkins.yml new file mode 100644 index 0000000..f368a8b --- /dev/null +++ b/ball-velocity/src/main/resources/jenkins.yml @@ -0,0 +1,6 @@ +BUILD_ID: ${BUILD_ID} +BUILD_NUMBER: ${BUILD_NUMBER} +BUILD_DISPLAY_NAME: ${BUILD_DISPLAY_NAME} +JOB_URL: ${JOB_URL} +BUILD_URL: ${BUILD_URL} +GIT_COMMIT: ${GIT_COMMIT} \ No newline at end of file diff --git a/ball-velocity/src/main/templates/cn/hamster3/mc/plugin/ball/velocity/BuildConstants.java b/ball-velocity/src/main/templates/cn/hamster3/mc/plugin/ball/velocity/BuildConstants.java new file mode 100644 index 0000000..06bc3e0 --- /dev/null +++ b/ball-velocity/src/main/templates/cn/hamster3/mc/plugin/ball/velocity/BuildConstants.java @@ -0,0 +1,8 @@ +package cn.hamster3.mc.plugin.ball.velocity; + +// The constants are replaced before compilation +@SuppressWarnings("unused") +public class BuildConstants { + public static final String VERSION = "${version}"; + public static final String DESCRIPTION = "${description}"; +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 689e8bc..c81058e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -9,3 +9,4 @@ rootProject.name = "hamster-ball" include("ball-common") include("ball-bukkit") include("ball-bungee") +include("ball-velocity")