feat: 适配新版API更新
This commit is contained in:
41
ball-bungeecord/build.gradle
Normal file
41
ball-bungeecord/build.gradle
Normal file
@@ -0,0 +1,41 @@
|
||||
setArchivesBaseName("HamsterBall-BungeeCord")
|
||||
|
||||
evaluationDependsOn(':ball-common')
|
||||
|
||||
dependencies {
|
||||
apiShade project(":ball-common") transitive false
|
||||
|
||||
//noinspection VulnerableLibrariesLocal
|
||||
compileOnly 'net.md-5:bungeecord-api:1.19-R0.1-SNAPSHOT' exclude group: 'io.netty'
|
||||
|
||||
compileOnly "cn.hamster3.mc.plugin:core-bungeecord:${hamster_core_version}"
|
||||
}
|
||||
|
||||
processResources {
|
||||
inputs.property "version", project.version
|
||||
filesMatching("bungee.yml") {
|
||||
expand "version": project.version
|
||||
}
|
||||
duplicatesStrategy(DuplicatesStrategy.EXCLUDE)
|
||||
}
|
||||
|
||||
tasks.compileJava.dependsOn(":ball-common:build")
|
||||
tasks.register("shadowJar", Jar) {
|
||||
dependsOn("jar")
|
||||
from([
|
||||
tasks.jar.outputs.files.collect {
|
||||
it.isDirectory() ? it : zipTree(it)
|
||||
},
|
||||
configurations.shade.collect {
|
||||
it.isDirectory() ? it : zipTree(it)
|
||||
},
|
||||
configurations.apiShade.collect {
|
||||
it.isDirectory() ? it : zipTree(it)
|
||||
},
|
||||
configurations.implementationShade.collect {
|
||||
it.isDirectory() ? it : zipTree(it)
|
||||
}
|
||||
])
|
||||
destinationDir(rootProject.buildDir)
|
||||
}
|
||||
tasks.build.dependsOn(shadowJar)
|
@@ -0,0 +1,69 @@
|
||||
package cn.hamster3.mc.plugin.core.bungee;
|
||||
|
||||
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.server.ServerOnlineEvent;
|
||||
import cn.hamster3.mc.plugin.core.bungee.api.BallBungeeCordAPI;
|
||||
import cn.hamster3.mc.plugin.core.bungee.listener.BallBungeeCordListener;
|
||||
import cn.hamster3.mc.plugin.core.bungee.util.BallBungeeCordUtils;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class HamsterBallPlugin extends Plugin {
|
||||
private static HamsterBallPlugin instance;
|
||||
|
||||
public static HamsterBallPlugin getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
instance = this;
|
||||
Logger logger = getLogger();
|
||||
BallBungeeCordAPI.init();
|
||||
logger.info("BallBungeeCordAPI 已初始化.");
|
||||
try {
|
||||
BallBungeeCordAPI.getInstance().enable();
|
||||
logger.info("BallBungeeCordAPI 已启动.");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
ProxyServer.getInstance().stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
Logger logger = getLogger();
|
||||
if (!BallAPI.getInstance().isConnected()) {
|
||||
ProxyServer.getInstance().stop("由于 HamsterBall 未能成功连接, 服务器将立即关闭.");
|
||||
return;
|
||||
}
|
||||
ProxyServer.getInstance().getPluginManager().registerListener(this, BallBungeeCordListener.INSTANCE);
|
||||
logger.info("已注册 BallBungeeCordListener.");
|
||||
BallAPI.getInstance().sendBallMessage(
|
||||
BallAPI.BALL_CHANNEL,
|
||||
ServerOnlineEvent.ACTION,
|
||||
new ServerOnlineEvent(BallAPI.getInstance().getLocalServerInfo())
|
||||
);
|
||||
logger.info("HamsterBall 已启动.");
|
||||
BallAPI.getInstance().getAllPlayerInfo().values()
|
||||
.stream()
|
||||
.filter(BallPlayerInfo::isOnline)
|
||||
.filter(o -> BallAPI.getInstance().isLocalServer(o.getProxyServer()))
|
||||
.forEach(playerInfo -> {
|
||||
playerInfo.setOnline(false);
|
||||
BallBungeeCordUtils.uploadPlayerInfo(playerInfo);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
try {
|
||||
BallBungeeCordAPI.getInstance().disable();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
package cn.hamster3.mc.plugin.core.bungee.api;
|
||||
|
||||
import cn.hamster3.mc.plugin.ball.common.api.BallAPI;
|
||||
import cn.hamster3.mc.plugin.ball.common.config.BallConfig;
|
||||
import cn.hamster3.mc.plugin.ball.common.entity.BallServerInfo;
|
||||
import cn.hamster3.mc.plugin.ball.common.entity.BallServerType;
|
||||
import cn.hamster3.mc.plugin.ball.common.listener.BallDebugListener;
|
||||
import cn.hamster3.mc.plugin.core.bungee.HamsterBallPlugin;
|
||||
import cn.hamster3.mc.plugin.core.bungee.listener.BallBungeeCordListener;
|
||||
import cn.hamster3.mc.plugin.core.bungee.util.CoreBungeeCordUtils;
|
||||
import net.md_5.bungee.config.Configuration;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class BallBungeeCordAPI extends BallAPI {
|
||||
public BallBungeeCordAPI(@NotNull BallConfig config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
public static BallBungeeCordAPI getInstance() {
|
||||
return (BallBungeeCordAPI) instance;
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
if (instance != null) {
|
||||
return;
|
||||
}
|
||||
HamsterBallPlugin plugin = HamsterBallPlugin.getInstance();
|
||||
Configuration pluginConfig = CoreBungeeCordUtils.getPluginConfig(plugin);
|
||||
Map<String, String> env = System.getenv();
|
||||
|
||||
String serverInfoID = env.getOrDefault("BALL_SERVER_INFO_ID",
|
||||
pluginConfig.getString("server-info.id"));
|
||||
String serverInfoName = env.getOrDefault("BALL_SERVER_INFO_NAME",
|
||||
pluginConfig.getString("server-info.name"));
|
||||
String serverInfoHost = env.getOrDefault("SERVER_IP",
|
||||
pluginConfig.getString("server-info.host", "0.0.0.0"));
|
||||
int serverInfoPort = Integer.parseInt(env.getOrDefault("SERVER_PORT",
|
||||
String.valueOf(pluginConfig.getInt("server-info.port", 25577))));
|
||||
BallServerInfo serverInfo = new BallServerInfo(
|
||||
serverInfoID,
|
||||
serverInfoName,
|
||||
BallServerType.PROXY,
|
||||
serverInfoHost,
|
||||
serverInfoPort
|
||||
);
|
||||
|
||||
String serverHost = env.getOrDefault("BALL_SERVER_HOST",
|
||||
pluginConfig.getString("ball-server.host", "ball.hamster3.cn"));
|
||||
int serverPort = Integer.parseInt(env.getOrDefault("BALL_SERVER_PORT",
|
||||
String.valueOf(pluginConfig.getInt("ball-server.port", 58888))));
|
||||
int eventLoopThread = Integer.parseInt(env.getOrDefault("BALL_EVENT_LOOP_THREAD",
|
||||
String.valueOf(pluginConfig.getInt("ball-server.event-loop-thread", 2))));
|
||||
BallConfig config = new BallConfig(serverInfo, serverHost, serverPort, eventLoopThread);
|
||||
|
||||
instance = new BallBungeeCordAPI(config);
|
||||
|
||||
instance.addListener(BallBungeeCordListener.INSTANCE);
|
||||
if (pluginConfig.getBoolean("debug", false)) {
|
||||
instance.addListener(BallDebugListener.INSTANCE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enable() throws SQLException, InterruptedException {
|
||||
super.enable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() throws SQLException, InterruptedException {
|
||||
super.disable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Logger getLogger() {
|
||||
return HamsterBallPlugin.getInstance().getLogger();
|
||||
}
|
||||
}
|
@@ -0,0 +1,211 @@
|
||||
package cn.hamster3.mc.plugin.core.bungee.listener;
|
||||
|
||||
import cn.hamster3.mc.plugin.ball.common.api.BallAPI;
|
||||
import cn.hamster3.mc.plugin.ball.common.data.BallMessageInfo;
|
||||
import cn.hamster3.mc.plugin.ball.common.entity.BallPlayerInfo;
|
||||
import cn.hamster3.mc.plugin.ball.common.entity.BallServerType;
|
||||
import cn.hamster3.mc.plugin.ball.common.event.operate.*;
|
||||
import cn.hamster3.mc.plugin.ball.common.event.player.*;
|
||||
import cn.hamster3.mc.plugin.ball.common.listener.BallListener;
|
||||
import cn.hamster3.mc.plugin.core.bungee.HamsterBallPlugin;
|
||||
import cn.hamster3.mc.plugin.core.bungee.util.BallBungeeCordUtils;
|
||||
import cn.hamster3.mc.plugin.core.common.api.CoreAPI;
|
||||
import cn.hamster3.mc.plugin.core.common.util.CoreUtils;
|
||||
import cn.hamster3.mc.plugin.core.lib.net.kyori.adventure.audience.Audience;
|
||||
import cn.hamster3.mc.plugin.core.lib.net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.*;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.md_5.bungee.event.EventPriority;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public final class BallBungeeCordListener implements Listener, BallListener {
|
||||
public static final BallBungeeCordListener INSTANCE = new BallBungeeCordListener();
|
||||
|
||||
private BallBungeeCordListener() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageReceived(@NotNull BallMessageInfo info) {
|
||||
switch (info.getAction()) {
|
||||
case DispatchConsoleCommandEvent.ACTION: {
|
||||
DispatchConsoleCommandEvent event = CoreUtils.GSON.fromJson(info.getContent(), DispatchConsoleCommandEvent.class);
|
||||
if (event.getType() != null && event.getType() != BallServerType.PROXY) {
|
||||
return;
|
||||
}
|
||||
if (event.getServerID() != null && !BallAPI.getInstance().isLocalServer(event.getServerID())) {
|
||||
return;
|
||||
}
|
||||
ProxyServer server = ProxyServer.getInstance();
|
||||
server.getPluginManager().dispatchCommand(server.getConsole(), event.getCommand());
|
||||
break;
|
||||
}
|
||||
case DispatchPlayerCommandEvent.ACTION: {
|
||||
DispatchPlayerCommandEvent event = CoreUtils.GSON.fromJson(info.getContent(), DispatchPlayerCommandEvent.class);
|
||||
if (event.getType() != null && event.getType() != BallServerType.GAME) {
|
||||
return;
|
||||
}
|
||||
ProxyServer server = ProxyServer.getInstance();
|
||||
if (event.getUuid() != null) {
|
||||
ProxiedPlayer player = server.getPlayer(event.getUuid());
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
server.getPluginManager().dispatchCommand(player, event.getCommand());
|
||||
return;
|
||||
}
|
||||
for (ProxiedPlayer player : server.getPlayers()) {
|
||||
server.getPluginManager().dispatchCommand(player, event.getCommand());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KickPlayerEvent.ACTION: {
|
||||
KickPlayerEvent event = CoreUtils.GSON.fromJson(info.getContent(), KickPlayerEvent.class);
|
||||
ProxiedPlayer player = ProxyServer.getInstance().getPlayer(event.getUuid());
|
||||
BaseComponent[] components = BungeeComponentSerializer.get().serialize(event.getReason());
|
||||
player.disconnect(components);
|
||||
break;
|
||||
}
|
||||
case SendMessageToPlayerEvent.ACTION: {
|
||||
SendMessageToPlayerEvent event = CoreUtils.GSON.fromJson(info.getContent(), SendMessageToPlayerEvent.class);
|
||||
for (UUID receiver : event.getReceivers()) {
|
||||
Audience audience = CoreAPI.getInstance().getAudienceProvider().player(receiver);
|
||||
event.getMessage().show(audience);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SendPlayerToLocationEvent.ACTION: {
|
||||
SendPlayerToLocationEvent event = CoreUtils.GSON.fromJson(info.getContent(), SendPlayerToLocationEvent.class);
|
||||
String serverID = event.getLocation().getServerID();
|
||||
ServerInfo serverInfo = ProxyServer.getInstance().getServerInfo(serverID);
|
||||
if (serverInfo == null) {
|
||||
HamsterBallPlugin.getInstance().getLogger().warning("试图传送玩家时失败: 服务器 " + serverID + " 不在线!");
|
||||
break;
|
||||
}
|
||||
for (UUID uuid : event.getSendPlayerUUID()) {
|
||||
ProxiedPlayer player = ProxyServer.getInstance().getPlayer(uuid);
|
||||
if (player == null) {
|
||||
continue;
|
||||
}
|
||||
if (player.getServer().getInfo().getName().equals(serverID)) {
|
||||
continue;
|
||||
}
|
||||
player.connect(serverInfo);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SendPlayerToPlayerEvent.ACTION: {
|
||||
SendPlayerToPlayerEvent event = CoreUtils.GSON.fromJson(info.getContent(), SendPlayerToPlayerEvent.class);
|
||||
UUID toPlayerUUID = event.getToPlayerUUID();
|
||||
ProxiedPlayer toPlayer = ProxyServer.getInstance().getPlayer(toPlayerUUID);
|
||||
if (toPlayer == null) {
|
||||
HamsterBallPlugin.getInstance().getLogger().warning("试图传送玩家时失败: 目标玩家 " + toPlayerUUID + " 不在线!");
|
||||
break;
|
||||
}
|
||||
ServerInfo toServer = toPlayer.getServer().getInfo();
|
||||
for (UUID uuid : event.getSendPlayerUUID()) {
|
||||
ProxiedPlayer sendPlayer = ProxyServer.getInstance().getPlayer(uuid);
|
||||
if (sendPlayer.getServer().getInfo().getName().equals(toServer.getName())) {
|
||||
continue;
|
||||
}
|
||||
sendPlayer.connect(toServer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDead() {
|
||||
ProxyServer.getInstance().stop("HamsterBall 重连失败.");
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onPreLogin(PreLoginEvent event) {
|
||||
BallAPI.getInstance().sendBallMessage(
|
||||
BallAPI.BALL_CHANNEL,
|
||||
BallPlayerPreLoginEvent.ACTION,
|
||||
new BallPlayerPreLoginEvent(event.getConnection().getName())
|
||||
);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onLogin(LoginEvent event) {
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
BallAPI.getInstance().sendBallMessage(
|
||||
BallAPI.BALL_CHANNEL,
|
||||
BallPlayerLoginEvent.ACTION,
|
||||
new BallPlayerLoginEvent(new BallPlayerInfo(
|
||||
event.getConnection().getUniqueId(),
|
||||
event.getConnection().getName(),
|
||||
"connecting",
|
||||
BallAPI.getInstance().getLocalServerId(),
|
||||
true
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onPostLogin(PostLoginEvent event) {
|
||||
ProxiedPlayer player = event.getPlayer();
|
||||
BallPlayerInfo playerInfo = BallBungeeCordUtils.getPlayerInfo(player, true);
|
||||
BallAPI.getInstance().sendBallMessage(
|
||||
BallAPI.BALL_CHANNEL,
|
||||
BallPlayerPostLoginEvent.ACTION,
|
||||
new BallPlayerPostLoginEvent(playerInfo)
|
||||
);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onServerConnect(ServerConnectEvent event) {
|
||||
ProxiedPlayer player = event.getPlayer();
|
||||
BallPlayerInfo playerInfo = BallBungeeCordUtils.getPlayerInfo(player, true);
|
||||
playerInfo.setGameServer(event.getTarget().getName());
|
||||
BallAPI.getInstance().sendBallMessage(
|
||||
BallAPI.BALL_CHANNEL,
|
||||
BallPlayerPreConnectServerEvent.ACTION,
|
||||
new BallPlayerPreConnectServerEvent(playerInfo, playerInfo.getGameServer(), event.getTarget().getName())
|
||||
);
|
||||
BallBungeeCordUtils.uploadPlayerInfo(playerInfo);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onServerConnected(ServerConnectedEvent event) {
|
||||
ProxiedPlayer player = event.getPlayer();
|
||||
BallPlayerInfo playerInfo = BallBungeeCordUtils.getPlayerInfo(player, true);
|
||||
playerInfo.setGameServer(event.getServer().getInfo().getName());
|
||||
BallAPI.getInstance().sendBallMessage(
|
||||
BallAPI.BALL_CHANNEL,
|
||||
BallPlayerPostConnectServerEvent.ACTION,
|
||||
new BallPlayerPostConnectServerEvent(playerInfo)
|
||||
);
|
||||
BallBungeeCordUtils.uploadPlayerInfo(playerInfo);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onServerSwitch(ServerSwitchEvent event) {
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onServerDisconnect(ServerDisconnectEvent event) {
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onPlayerDisconnect(PlayerDisconnectEvent event) {
|
||||
ProxiedPlayer player = event.getPlayer();
|
||||
BallPlayerInfo playerInfo = BallBungeeCordUtils.getPlayerInfo(player, false);
|
||||
BallAPI.getInstance().sendBallMessage(
|
||||
BallAPI.BALL_CHANNEL,
|
||||
BallPlayerLogoutEvent.ACTION,
|
||||
new BallPlayerLogoutEvent(playerInfo)
|
||||
);
|
||||
BallBungeeCordUtils.uploadPlayerInfo(playerInfo);
|
||||
}
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
package cn.hamster3.mc.plugin.core.bungee.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.player.BallPlayerInfoUpdateEvent;
|
||||
import cn.hamster3.mc.plugin.core.common.api.CoreAPI;
|
||||
import cn.hamster3.mc.plugin.core.common.util.CoreUtils;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.connection.Server;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public final class BallBungeeCordUtils {
|
||||
private BallBungeeCordUtils() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static BallPlayerInfo getPlayerInfo(@NotNull ProxiedPlayer player, boolean online) {
|
||||
Server server = player.getServer();
|
||||
return new BallPlayerInfo(
|
||||
player.getUniqueId(),
|
||||
player.getName(),
|
||||
server == null ? "connecting" : server.getInfo().getName(),
|
||||
BallAPI.getInstance().getLocalServerId(),
|
||||
online
|
||||
);
|
||||
}
|
||||
|
||||
public static void uploadPlayerInfo(@NotNull BallPlayerInfo playerInfo) {
|
||||
CoreUtils.WORKER_EXECUTOR.execute(() -> {
|
||||
try (Connection connection = CoreAPI.getInstance().getConnection()) {
|
||||
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();
|
||||
statement.close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
BallAPI.getInstance().sendBallMessage(
|
||||
BallAPI.BALL_CHANNEL,
|
||||
BallPlayerInfoUpdateEvent.ACTION,
|
||||
new BallPlayerInfoUpdateEvent(playerInfo)
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
9
ball-bungeecord/src/main/resources/bungee.yml
Normal file
9
ball-bungeecord/src/main/resources/bungee.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
name: HamsterBall
|
||||
main: cn.hamster3.mc.plugin.core.bungee.HamsterBallPlugin
|
||||
version: ${version}
|
||||
|
||||
author: MiniDay
|
||||
description: 仓鼠球:一个基于 Netty 的 Minecraft 服务端通用消息中间件(原HamsterService)
|
||||
|
||||
depend:
|
||||
- HamsterCore
|
15
ball-bungeecord/src/main/resources/config.yml
Normal file
15
ball-bungeecord/src/main/resources/config.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
# 是否允许在控制台输出调试信息
|
||||
debug: false
|
||||
|
||||
ball-server:
|
||||
host: "ball.hamster3.cn"
|
||||
port: 58888
|
||||
event-loop-thread: 5
|
||||
|
||||
server-info:
|
||||
# 服务器唯一识别码,最长 32 字符
|
||||
id: "BungeeCord"
|
||||
# 服务端名称,用于展示给玩家看
|
||||
name: "代理端"
|
||||
host: 0.0.0.0
|
||||
port: 25577
|
Reference in New Issue
Block a user