From 31109849fec25c9e591380dcff0e58630f11544d Mon Sep 17 00:00:00 2001 From: TONY_All Date: Sun, 16 Apr 2023 09:31:37 +0800 Subject: [PATCH] Sync --- README.md | 4 +- .../cc/maxmc/msm/api/MultiServerManAPI.java | 7 ++- .../java/cc/maxmc/msm/api/misc/MatchInfo.java | 42 +++++++++++++++ .../cc/maxmc/msm/api/misc/ServerInfo.java | 50 +++++++++++------ child/src/main/kotlin/Run.kt | 10 ---- .../cc/maxmc/msm/child/MultiServerMan.kt | 6 ++- .../kotlin/cc/maxmc/msm/child/api/APIImpl.kt | 10 ++-- .../{api => listener}/APIPacketListener.kt | 8 +-- .../msm/child/listener/ProtocolListener.kt | 53 +++++++++++++++++++ .../cc/maxmc/msm/child/misc/SubServer.kt | 16 +++--- .../cc/maxmc/msm/child/netty/NetClient.kt | 41 ++++++++------ child/src/main/resources/settings.yml | 9 +++- .../common/network/netty/NetworkRegistry.kt | 11 ++-- .../network/packet/CPacketAPICallback.kt | 23 ++++---- .../network/packet/CPacketRequestServer.kt | 12 +++-- .../common/network/packet/PPacketChildInfo.kt | 3 +- .../network/packet/PPacketServerStarted.kt | 19 +++++++ .../kotlin/cc/maxmc/msm/common/utils/Netty.kt | 20 +++++-- .../cc/maxmc/msm/parent/MultiServerMan.kt | 4 ++ .../main/kotlin/cc/maxmc/msm/parent/Run.kt | 9 ---- .../kotlin/cc/maxmc/msm/parent/api/APIImpl.kt | 21 ++++---- .../maxmc/msm/parent/database/SQLDatabase.kt | 13 +++-- .../msm/parent/listener/PacketListener.kt | 2 + .../maxmc/msm/parent/manager/ChildManager.kt | 10 ++-- .../maxmc/msm/parent/manager/MatchManager.kt | 27 ++++++++++ .../maxmc/msm/parent/manager/ServerManager.kt | 43 +++++++++++++-- .../cc/maxmc/msm/parent/misc/ChildBungee.kt | 23 ++++++-- .../cc/maxmc/msm/parent/netty/NetManager.kt | 10 ++-- .../cc/maxmc/msm/parent/settings/Settings.kt | 2 +- parent/src/main/resources/settings.yml | 5 +- 30 files changed, 369 insertions(+), 144 deletions(-) create mode 100644 api/src/main/java/cc/maxmc/msm/api/misc/MatchInfo.java delete mode 100644 child/src/main/kotlin/Run.kt rename child/src/main/kotlin/cc/maxmc/msm/child/{api => listener}/APIPacketListener.kt (88%) create mode 100644 child/src/main/kotlin/cc/maxmc/msm/child/listener/ProtocolListener.kt create mode 100644 common/src/main/kotlin/cc/maxmc/msm/common/network/packet/PPacketServerStarted.kt delete mode 100644 parent/src/main/kotlin/cc/maxmc/msm/parent/Run.kt create mode 100644 parent/src/main/kotlin/cc/maxmc/msm/parent/manager/MatchManager.kt diff --git a/README.md b/README.md index 49b0bf2..438af6b 100644 --- a/README.md +++ b/README.md @@ -109,4 +109,6 @@ api.getServer("default", players); A: 只提供服务器并记录玩家 -4. Q: 服务端是 \ No newline at end of file +4. Q: 服务端启动方式 + + A: 启动脚本,参数为端口+自定义参数 \ No newline at end of file diff --git a/api/src/main/java/cc/maxmc/msm/api/MultiServerManAPI.java b/api/src/main/java/cc/maxmc/msm/api/MultiServerManAPI.java index 5eea686..6033379 100644 --- a/api/src/main/java/cc/maxmc/msm/api/MultiServerManAPI.java +++ b/api/src/main/java/cc/maxmc/msm/api/MultiServerManAPI.java @@ -1,7 +1,6 @@ package cc.maxmc.msm.api; -import cc.maxmc.msm.api.misc.ServerInfo; -import net.md_5.bungee.api.connection.ProxiedPlayer; +import cc.maxmc.msm.api.misc.MatchInfo; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -9,12 +8,12 @@ import java.util.List; @SuppressWarnings("unused") // API public interface MultiServerManAPI { @NotNull - ServerInfo getServer(@NotNull String type, @NotNull List players); + MatchInfo getServer(@NotNull String type, @NotNull List players); void informEnd(int id); @NotNull - ServerInfo getPlayerServer(@NotNull String player); + MatchInfo getPlayerServer(@NotNull String player); Boolean containPlayer(@NotNull String player); diff --git a/api/src/main/java/cc/maxmc/msm/api/misc/MatchInfo.java b/api/src/main/java/cc/maxmc/msm/api/misc/MatchInfo.java new file mode 100644 index 0000000..5635cb3 --- /dev/null +++ b/api/src/main/java/cc/maxmc/msm/api/misc/MatchInfo.java @@ -0,0 +1,42 @@ +package cc.maxmc.msm.api.misc; + +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; + +public class MatchInfo { + private final int id; + @NotNull + private final ServerInfo info; + + public MatchInfo() { + id = -1; + info = new ServerInfo(); + } + + public MatchInfo(int id, @NotNull ServerInfo info) { + this.id = id; + this.info = info; + } + + public int getId() { + return id; + } + + public ServerInfo getServer() { + return info; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MatchInfo matchInfo = (MatchInfo) o; + return id == matchInfo.id && Objects.equals(info, matchInfo.info); + } + + @Override + public int hashCode() { + return Objects.hash(id, info); + } +} diff --git a/api/src/main/java/cc/maxmc/msm/api/misc/ServerInfo.java b/api/src/main/java/cc/maxmc/msm/api/misc/ServerInfo.java index 2480eae..90e0573 100644 --- a/api/src/main/java/cc/maxmc/msm/api/misc/ServerInfo.java +++ b/api/src/main/java/cc/maxmc/msm/api/misc/ServerInfo.java @@ -1,15 +1,34 @@ package cc.maxmc.msm.api.misc; -import com.google.common.net.HostAndPort; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Objects; +import java.util.UUID; + @SuppressWarnings("unused") // API public class ServerInfo { + @NotNull + private final UUID uid; @Nullable - private final HostAndPort server; - private final int id; + private final String server; private boolean available; + public ServerInfo() { + uid = UUID.fromString("00000000-0000-0000-0000-000000000000"); + server = null; + } + + public ServerInfo(@NotNull UUID uid, @Nullable String server) { + this.uid = uid; + this.server = server; + } + + @NotNull + public UUID getUid() { + return uid; + } + public boolean isAvailable() { return available; } @@ -18,22 +37,21 @@ public class ServerInfo { this.available = available; } - public ServerInfo() { - server = HostAndPort.fromString("127.0.0.1"); - id = -1; - } - - public ServerInfo(@Nullable HostAndPort server, int id) { - this.server = server; - this.id = id; - } - @Nullable - public HostAndPort getServer() { + public String getServer() { return server; } - public int getId() { - return id; + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ServerInfo that = (ServerInfo) o; + return Objects.equals(server, that.server) && Objects.equals(uid, that.uid); + } + + @Override + public int hashCode() { + return Objects.hash(server, uid); } } diff --git a/child/src/main/kotlin/Run.kt b/child/src/main/kotlin/Run.kt deleted file mode 100644 index b66871a..0000000 --- a/child/src/main/kotlin/Run.kt +++ /dev/null @@ -1,10 +0,0 @@ -import cc.maxmc.msm.child.misc.SubServer -import kotlin.io.path.Path - -suspend fun main() { - val server = SubServer(10086, "test", 25571, Path("/Users/tony_all/Servers/MSM/")) - server.initServer() - server.startServer() - Thread.sleep(10000) - server.cleanup() -} \ No newline at end of file diff --git a/child/src/main/kotlin/cc/maxmc/msm/child/MultiServerMan.kt b/child/src/main/kotlin/cc/maxmc/msm/child/MultiServerMan.kt index 3bf0480..fbff3f0 100644 --- a/child/src/main/kotlin/cc/maxmc/msm/child/MultiServerMan.kt +++ b/child/src/main/kotlin/cc/maxmc/msm/child/MultiServerMan.kt @@ -2,9 +2,10 @@ package cc.maxmc.msm.child import cc.maxmc.msm.api.MultiServerManAPIProvider import cc.maxmc.msm.child.api.APIImpl -import cc.maxmc.msm.child.api.APIPacketListener +import cc.maxmc.msm.child.listener.APIPacketListener import cc.maxmc.msm.child.command.Api import cc.maxmc.msm.child.command.Send +import cc.maxmc.msm.child.listener.ProtocolListener import cc.maxmc.msm.child.netty.NetClient import cc.maxmc.msm.child.settings.Settings import cc.maxmc.msm.common.network.netty.NetworkRegistry @@ -21,8 +22,9 @@ class MultiServerMan : Plugin() { ProxyServer.getInstance().pluginManager.registerCommand(this, Send) ProxyServer.getInstance().pluginManager.registerCommand(this, Api) ProxyServer.getInstance().pluginManager.registerListener(this, APIPacketListener) + ProxyServer.getInstance().pluginManager.registerListener(this, ProtocolListener) NetworkRegistry - NetClient.start(Settings.Parent.address, Settings.Parent.port) + NetClient.init(Settings.Parent.address, Settings.Parent.port) } override fun onDisable() { diff --git a/child/src/main/kotlin/cc/maxmc/msm/child/api/APIImpl.kt b/child/src/main/kotlin/cc/maxmc/msm/child/api/APIImpl.kt index dd8ce51..93c517d 100644 --- a/child/src/main/kotlin/cc/maxmc/msm/child/api/APIImpl.kt +++ b/child/src/main/kotlin/cc/maxmc/msm/child/api/APIImpl.kt @@ -1,7 +1,7 @@ package cc.maxmc.msm.child.api import cc.maxmc.msm.api.MultiServerManAPI -import cc.maxmc.msm.api.misc.ServerInfo +import cc.maxmc.msm.api.misc.MatchInfo import cc.maxmc.msm.child.netty.NetClient import cc.maxmc.msm.common.network.packet.PPacketAPICall import java.util.* @@ -13,10 +13,10 @@ object APIImpl : MultiServerManAPI { val apiCallCache = HashMap>() private const val TIMEOUT = 3L - override fun getServer(type: String, players: MutableList): ServerInfo { + override fun getServer(type: String, players: MutableList): MatchInfo { val packet = PPacketAPICall.PPacketCallGetServer(type, players) NetClient.sendPacket(packet) - val future = CompletableFuture() + val future = CompletableFuture() apiCallCache[packet.uid] = future as CompletableFuture return future.get(TIMEOUT, TimeUnit.SECONDS) } @@ -30,10 +30,10 @@ object APIImpl : MultiServerManAPI { return } - override fun getPlayerServer(player: String): ServerInfo { + override fun getPlayerServer(player: String): MatchInfo { val packet = PPacketAPICall.PPacketCallGetPlayerServer(player) NetClient.sendPacket(packet) - val future = CompletableFuture() + val future = CompletableFuture() apiCallCache[packet.uid] = future as CompletableFuture return future.get(TIMEOUT, TimeUnit.SECONDS) } diff --git a/child/src/main/kotlin/cc/maxmc/msm/child/api/APIPacketListener.kt b/child/src/main/kotlin/cc/maxmc/msm/child/listener/APIPacketListener.kt similarity index 88% rename from child/src/main/kotlin/cc/maxmc/msm/child/api/APIPacketListener.kt rename to child/src/main/kotlin/cc/maxmc/msm/child/listener/APIPacketListener.kt index 208882c..4da6b8a 100644 --- a/child/src/main/kotlin/cc/maxmc/msm/child/api/APIPacketListener.kt +++ b/child/src/main/kotlin/cc/maxmc/msm/child/listener/APIPacketListener.kt @@ -1,8 +1,8 @@ -package cc.maxmc.msm.child.api +package cc.maxmc.msm.child.listener +import cc.maxmc.msm.child.api.APIImpl import cc.maxmc.msm.common.event.PacketReceiveEvent import cc.maxmc.msm.common.network.packet.CPacketAPICallback -import cc.maxmc.msm.common.utils.debug import net.md_5.bungee.api.plugin.Listener import net.md_5.bungee.event.EventHandler @@ -21,12 +21,12 @@ object APIPacketListener : Listener { } is CPacketAPICallback.CPacketCallbackGetPlayerServer -> { - future?.complete(packet.serverInfo) + future?.complete(packet.matchInfo) ?: throw IllegalStateException("Packet callback received, however no request") } is CPacketAPICallback.CPacketCallbackGetServer -> { - future?.complete(packet.serverInfo) + future?.complete(packet.matchInfo) ?: throw IllegalStateException("Packet callback received, however no request") } diff --git a/child/src/main/kotlin/cc/maxmc/msm/child/listener/ProtocolListener.kt b/child/src/main/kotlin/cc/maxmc/msm/child/listener/ProtocolListener.kt new file mode 100644 index 0000000..65e519c --- /dev/null +++ b/child/src/main/kotlin/cc/maxmc/msm/child/listener/ProtocolListener.kt @@ -0,0 +1,53 @@ +package cc.maxmc.msm.child.listener + +import cc.maxmc.msm.child.MultiServerMan +import cc.maxmc.msm.child.misc.SubServer +import cc.maxmc.msm.child.netty.NetClient +import cc.maxmc.msm.child.settings.Settings +import cc.maxmc.msm.common.event.ChannelInactiveEvent +import cc.maxmc.msm.common.event.PacketReceiveEvent +import cc.maxmc.msm.common.network.packet.CPacketGetInfo +import cc.maxmc.msm.common.network.packet.CPacketRequestServer +import cc.maxmc.msm.common.network.packet.PPacketChildInfo +import cc.maxmc.msm.common.network.packet.PPacketServerStarted +import cc.maxmc.msm.common.utils.log +import cc.maxmc.msm.common.utils.pluginScope +import kotlinx.coroutines.launch +import net.md_5.bungee.api.plugin.Listener +import net.md_5.bungee.event.EventHandler +import java.util.* +import kotlin.io.path.isDirectory +import kotlin.io.path.listDirectoryEntries +import kotlin.io.path.name + +object ProtocolListener : Listener { + val serverCache = HashMap() + + @EventHandler + fun onGetInfo(packetE: PacketReceiveEvent) { + if (packetE.packet !is CPacketGetInfo) return + val types = MultiServerMan.instance.dataFolder.toPath().resolve("patterns").listDirectoryEntries() + .filter { it.isDirectory() }.map { it.name }.toMutableSet() + val packetCallBack = PPacketChildInfo(Settings.portRange.toHashSet(), types) + NetClient.sendPacket(packetCallBack) + } + + @EventHandler + fun onRequestServer(packetE: PacketReceiveEvent) { + val packet = packetE.packet as? CPacketRequestServer ?: return + val serverInfo = packet.serverInfo + val subServer = SubServer(serverInfo.uid, packet.type, serverInfo.server!!.split(":")[1].toInt()) + pluginScope.launch { + subServer.initServer() + subServer.startServer() + NetClient.sendPacket(PPacketServerStarted(serverInfo)) + } + } + + fun onDisconnect(packet: ChannelInactiveEvent) { + repeat(10) { + log("Remote Disconnected.") + } + } + +} \ No newline at end of file diff --git a/child/src/main/kotlin/cc/maxmc/msm/child/misc/SubServer.kt b/child/src/main/kotlin/cc/maxmc/msm/child/misc/SubServer.kt index 9661c9c..fc2b6e5 100644 --- a/child/src/main/kotlin/cc/maxmc/msm/child/misc/SubServer.kt +++ b/child/src/main/kotlin/cc/maxmc/msm/child/misc/SubServer.kt @@ -5,18 +5,19 @@ import cc.maxmc.msm.child.utils.ScriptRunner import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.nio.file.Path +import java.util.* +import kotlin.coroutines.resume +import kotlin.coroutines.suspendCoroutine import kotlin.io.path.copyToRecursively import kotlin.io.path.createDirectories import kotlin.io.path.deleteRecursively @OptIn(kotlin.io.path.ExperimentalPathApi::class) class SubServer( - val id: Int, - val type: String, - val port: Int, - baseFolder: Path = MultiServerMan.instance.dataFolder.toPath() + val uid: UUID, val type: String, val port: Int, baseFolder: Path = MultiServerMan.instance.dataFolder.toPath() ) { - private val serverFolder = baseFolder.resolve("cache").resolve(id.toString()).also { it.createDirectories() } + private val serverFolder = + baseFolder.resolve("cache").resolve(uid.toString().substring(0..7)).also { it.createDirectories() } private val patternFolder = baseFolder.resolve("pattern").resolve(type).also { it.createDirectories() } private val runner = ScriptRunner(serverFolder.resolve("start.sh")) @@ -24,16 +25,15 @@ class SubServer( patternFolder.copyToRecursively(serverFolder, followLinks = false, overwrite = true) } - fun startServer() { + suspend fun startServer() = suspendCoroutine { runner.launch(port.toString()) runner.onOutput("For help, type \"help\" or \"?\"") { - println("Started.") + it.resume(Unit) } } suspend fun cleanup() { runner.exec("stop") - println("Exec stop") runner.exit() serverFolder.deleteRecursively() } diff --git a/child/src/main/kotlin/cc/maxmc/msm/child/netty/NetClient.kt b/child/src/main/kotlin/cc/maxmc/msm/child/netty/NetClient.kt index 63d9682..37416b4 100644 --- a/child/src/main/kotlin/cc/maxmc/msm/child/netty/NetClient.kt +++ b/child/src/main/kotlin/cc/maxmc/msm/child/netty/NetClient.kt @@ -2,34 +2,45 @@ package cc.maxmc.msm.child.netty import cc.maxmc.msm.common.network.BungeePacket import cc.maxmc.msm.common.network.netty.NetworkRegistry +import cc.maxmc.msm.common.utils.log import cc.maxmc.msm.common.utils.pipelineInit +import cc.maxmc.msm.common.utils.pluginScope import io.netty.bootstrap.Bootstrap import io.netty.channel.Channel import io.netty.channel.ChannelFutureListener import io.netty.channel.ChannelOption import io.netty.channel.nio.NioEventLoopGroup import io.netty.channel.socket.nio.NioSocketChannel +import kotlinx.coroutines.* object NetClient { private val loop = NioEventLoopGroup() private lateinit var channel: Channel + private lateinit var boot: Bootstrap - fun start(address: String, port: Int) { - val future = Bootstrap() - .channel(NioSocketChannel::class.java) - .group(loop) - .handler(pipelineInit(NetworkRegistry.PacketDirection.CHILD_BOUND)) - .option(ChannelOption.TCP_NODELAY, true) + fun init(address: String, port: Int) { + boot = Bootstrap().channel(NioSocketChannel::class.java).group(loop) + .handler(pipelineInit(NetworkRegistry.PacketDirection.CHILD_BOUND)).option(ChannelOption.TCP_NODELAY, true) .remoteAddress(address, port) - .connect().addListener(ChannelFutureListener { - val result = it.cause() ?: return@ChannelFutureListener println( - "§a| §7成功连接到集群的主节点. (${ - it.channel().remoteAddress() - })" - ) - result.printStackTrace() - }) - channel = future.channel() + runBlocking { + connect(0) + } + } + + private suspend fun connect(delay: Long = 3000) { + delay(delay) + log("§b| §7正在尝试连接主BC") + val future = boot.connect().await() + val result = future.cause() + if (result == null) { + channel = future.channel() + log("§a| §7成功连接到集群的主节点. (${future.channel().remoteAddress()})") + return + } + log("§c| §7未能连接到主BC,将在 §c3s §7后重新连接。(原因: ${result.message})") + withContext(Dispatchers.IO) { + connect() + } } fun sendPacket(packet: BungeePacket) { diff --git a/child/src/main/resources/settings.yml b/child/src/main/resources/settings.yml index 301dcf6..15af0bd 100644 --- a/child/src/main/resources/settings.yml +++ b/child/src/main/resources/settings.yml @@ -1,7 +1,14 @@ +# 主BC的地址及端口 parent: address: 127.0.0.1 port: 23333 + +# 该子BC所在机器所能开放的端口 ports: - 30000 - 30001..30019 - - 30443 + +# 该子BC所支持的服务端模版类型及模版类型启动所需参数 +patterns: + main: + args: [ "-ListenPort=${port}", "-usr=usr", "-pwd=pwd" ] \ No newline at end of file diff --git a/common/src/main/kotlin/cc/maxmc/msm/common/network/netty/NetworkRegistry.kt b/common/src/main/kotlin/cc/maxmc/msm/common/network/netty/NetworkRegistry.kt index 38b617a..c89bd6a 100644 --- a/common/src/main/kotlin/cc/maxmc/msm/common/network/netty/NetworkRegistry.kt +++ b/common/src/main/kotlin/cc/maxmc/msm/common/network/netty/NetworkRegistry.kt @@ -1,11 +1,7 @@ package cc.maxmc.msm.common.network.netty import cc.maxmc.msm.common.network.BungeePacket -import cc.maxmc.msm.common.network.packet.CPacketAPICallback -import cc.maxmc.msm.common.network.packet.CPacketDebug -import cc.maxmc.msm.common.network.packet.PPacketAPICall -import cc.maxmc.msm.common.network.packet.PPacketDebug -import cc.maxmc.msm.common.utils.debug +import cc.maxmc.msm.common.network.packet.* import com.google.common.collect.HashBiMap object NetworkRegistry { @@ -18,11 +14,16 @@ object NetworkRegistry { registerPacket(PacketDirection.PARENT_BOUND, PPacketAPICall.PPacketCallContainPlayer::class.java) registerPacket(PacketDirection.PARENT_BOUND, PPacketAPICall.PPacketCallInformEnd::class.java) registerPacket(PacketDirection.PARENT_BOUND, PPacketAPICall.PPacketCallGetServer::class.java) + registerPacket(PacketDirection.PARENT_BOUND, PPacketServerStarted::class.java) + registerPacket(PacketDirection.PARENT_BOUND, PPacketChildInfo::class.java) registerPacket(PacketDirection.CHILD_BOUND, CPacketDebug::class.java) registerPacket(PacketDirection.CHILD_BOUND, CPacketAPICallback.CPacketCallbackGetPlayerServer::class.java) registerPacket(PacketDirection.CHILD_BOUND, CPacketAPICallback.CPacketCallbackContainPlayer::class.java) registerPacket(PacketDirection.CHILD_BOUND, CPacketAPICallback.CPacketCallbackInformEnd::class.java) registerPacket(PacketDirection.CHILD_BOUND, CPacketAPICallback.CPacketCallbackGetServer::class.java) + registerPacket(PacketDirection.CHILD_BOUND, CPacketRequestServer::class.java) + registerPacket(PacketDirection.CHILD_BOUND, CPacketGetInfo::class.java) + } private fun registerPacket(direction: PacketDirection, packet: Class) { diff --git a/common/src/main/kotlin/cc/maxmc/msm/common/network/packet/CPacketAPICallback.kt b/common/src/main/kotlin/cc/maxmc/msm/common/network/packet/CPacketAPICallback.kt index 8027bfd..a010eed 100644 --- a/common/src/main/kotlin/cc/maxmc/msm/common/network/packet/CPacketAPICallback.kt +++ b/common/src/main/kotlin/cc/maxmc/msm/common/network/packet/CPacketAPICallback.kt @@ -1,9 +1,9 @@ package cc.maxmc.msm.common.network.packet -import cc.maxmc.msm.api.misc.ServerInfo +import cc.maxmc.msm.api.misc.MatchInfo import cc.maxmc.msm.common.network.BungeePacket -import cc.maxmc.msm.common.utils.readServerInfo -import cc.maxmc.msm.common.utils.writeServerInfo +import cc.maxmc.msm.common.utils.readMatchInfo +import cc.maxmc.msm.common.utils.writeMatchInfo import io.netty.buffer.ByteBuf import net.md_5.bungee.protocol.DefinedPacket import java.util.* @@ -20,17 +20,16 @@ sealed class CPacketAPICallback( } class CPacketCallbackGetServer( - var serverInfo: ServerInfo = ServerInfo(), - uid: UUID = UUID.randomUUID() + var matchInfo: MatchInfo = MatchInfo(), uid: UUID = UUID.randomUUID() ) : CPacketAPICallback(uid = uid) { override fun encode(buf: ByteBuf) { super.encode(buf) - buf.writeServerInfo(serverInfo) + buf.writeMatchInfo(matchInfo) } override fun decode(buf: ByteBuf) { super.decode(buf) - serverInfo = buf.readServerInfo() + matchInfo = buf.readMatchInfo() } } @@ -39,23 +38,21 @@ sealed class CPacketAPICallback( ) : CPacketAPICallback(uid = uid) class CPacketCallbackGetPlayerServer( - var serverInfo: ServerInfo, - uid: UUID = UUID.randomUUID() + var matchInfo: MatchInfo, uid: UUID = UUID.randomUUID() ) : CPacketAPICallback(uid = uid) { override fun encode(buf: ByteBuf) { super.encode(buf) - buf.writeServerInfo(serverInfo) + buf.writeMatchInfo(matchInfo) } override fun decode(buf: ByteBuf) { super.decode(buf) - serverInfo = buf.readServerInfo() + matchInfo = buf.readMatchInfo() } } class CPacketCallbackContainPlayer( - var value: Boolean, - uid: UUID = UUID.randomUUID() + var value: Boolean, uid: UUID = UUID.randomUUID() ) : CPacketAPICallback(uid = uid) { override fun encode(buf: ByteBuf) { super.encode(buf) diff --git a/common/src/main/kotlin/cc/maxmc/msm/common/network/packet/CPacketRequestServer.kt b/common/src/main/kotlin/cc/maxmc/msm/common/network/packet/CPacketRequestServer.kt index 6a9bcf8..62a00b1 100644 --- a/common/src/main/kotlin/cc/maxmc/msm/common/network/packet/CPacketRequestServer.kt +++ b/common/src/main/kotlin/cc/maxmc/msm/common/network/packet/CPacketRequestServer.kt @@ -1,21 +1,23 @@ package cc.maxmc.msm.common.network.packet +import cc.maxmc.msm.api.misc.ServerInfo import cc.maxmc.msm.common.network.BungeePacket +import cc.maxmc.msm.common.utils.readServerInfo +import cc.maxmc.msm.common.utils.writeServerInfo import io.netty.buffer.ByteBuf import net.md_5.bungee.protocol.DefinedPacket -import java.util.* class CPacketRequestServer( - var type: String, - var uid: UUID = UUID.randomUUID() + var type: String = "", + var serverInfo: ServerInfo = ServerInfo(), ) : BungeePacket() { override fun encode(buf: ByteBuf) { - DefinedPacket.writeUUID(uid, buf) DefinedPacket.writeString(type, buf) + buf.writeServerInfo(serverInfo) } override fun decode(buf: ByteBuf) { - uid = DefinedPacket.readUUID(buf) type = DefinedPacket.readString(buf) + serverInfo = buf.readServerInfo() } } \ No newline at end of file diff --git a/common/src/main/kotlin/cc/maxmc/msm/common/network/packet/PPacketChildInfo.kt b/common/src/main/kotlin/cc/maxmc/msm/common/network/packet/PPacketChildInfo.kt index 05dbcea..1073197 100644 --- a/common/src/main/kotlin/cc/maxmc/msm/common/network/packet/PPacketChildInfo.kt +++ b/common/src/main/kotlin/cc/maxmc/msm/common/network/packet/PPacketChildInfo.kt @@ -4,7 +4,8 @@ import cc.maxmc.msm.common.network.BungeePacket import io.netty.buffer.ByteBuf import net.md_5.bungee.protocol.DefinedPacket -class PPacketChildInfo(var portRange: MutableSet = HashSet(), var types: MutableSet) : BungeePacket() { +class PPacketChildInfo(var portRange: MutableSet = HashSet(), var types: MutableSet = HashSet()) : + BungeePacket() { override fun encode(buf: ByteBuf) { DefinedPacket.writeVarInt(portRange.size, buf) portRange.forEach { diff --git a/common/src/main/kotlin/cc/maxmc/msm/common/network/packet/PPacketServerStarted.kt b/common/src/main/kotlin/cc/maxmc/msm/common/network/packet/PPacketServerStarted.kt new file mode 100644 index 0000000..416b187 --- /dev/null +++ b/common/src/main/kotlin/cc/maxmc/msm/common/network/packet/PPacketServerStarted.kt @@ -0,0 +1,19 @@ +package cc.maxmc.msm.common.network.packet + +import cc.maxmc.msm.api.misc.ServerInfo +import cc.maxmc.msm.common.network.BungeePacket +import cc.maxmc.msm.common.utils.readServerInfo +import cc.maxmc.msm.common.utils.writeServerInfo +import io.netty.buffer.ByteBuf + +class PPacketServerStarted( + var serverInfo: ServerInfo = ServerInfo() +) : BungeePacket() { + override fun encode(buf: ByteBuf) { + buf.writeServerInfo(serverInfo) + } + + override fun decode(buf: ByteBuf) { + serverInfo = buf.readServerInfo() + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/cc/maxmc/msm/common/utils/Netty.kt b/common/src/main/kotlin/cc/maxmc/msm/common/utils/Netty.kt index db4c360..8d50f0e 100644 --- a/common/src/main/kotlin/cc/maxmc/msm/common/utils/Netty.kt +++ b/common/src/main/kotlin/cc/maxmc/msm/common/utils/Netty.kt @@ -1,10 +1,10 @@ package cc.maxmc.msm.common.utils +import cc.maxmc.msm.api.misc.MatchInfo import cc.maxmc.msm.api.misc.ServerInfo import cc.maxmc.msm.common.network.ClusterPacketHandler import cc.maxmc.msm.common.network.netty.ClusterMsgCodec import cc.maxmc.msm.common.network.netty.NetworkRegistry -import com.google.common.net.HostAndPort import io.netty.buffer.ByteBuf import io.netty.channel.Channel import io.netty.channel.ChannelInitializer @@ -27,15 +27,25 @@ fun pipelineInit(direction: NetworkRegistry.PacketDirection) = channelInit): ServerInfo { - TODO("not implemented") - return ServerInfo(HostAndPort.fromString("127.0.0.1:23456"), 1024) + override fun getServer(type: String, players: List): MatchInfo { + return MatchManager.requestMatch(type, players) } override fun informEnd(id: Int) { - TODO("not implemented") - return + MatchManager.endMatch(id) } - override fun getPlayerServer(player: String): ServerInfo { - TODO("not implemented") - return ServerInfo(HostAndPort.fromString("127.0.0.1:34567"), 1025) + override fun getPlayerServer(player: String): MatchInfo { + return SQLDatabase.getPlayerMatch(player) } override fun containPlayer(player: String): Boolean { - TODO("not implemented") - return true + return getPlayerServer(player).id != -1 } } \ No newline at end of file diff --git a/parent/src/main/kotlin/cc/maxmc/msm/parent/database/SQLDatabase.kt b/parent/src/main/kotlin/cc/maxmc/msm/parent/database/SQLDatabase.kt index b3ca306..5522f81 100644 --- a/parent/src/main/kotlin/cc/maxmc/msm/parent/database/SQLDatabase.kt +++ b/parent/src/main/kotlin/cc/maxmc/msm/parent/database/SQLDatabase.kt @@ -1,11 +1,13 @@ package cc.maxmc.msm.parent.database +import cc.maxmc.msm.api.misc.MatchInfo +import cc.maxmc.msm.parent.manager.MatchManager import cc.maxmc.msm.parent.settings.Settings import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.pool.HikariPool import java.sql.Timestamp -class SQLDatabase { +object SQLDatabase { private val config = HikariConfig() private lateinit var pool: HikariPool fun initDatabase() { @@ -36,21 +38,22 @@ class SQLDatabase { } } - fun getPlayerMatch(player: String): Int { + fun getPlayerMatch(player: String): MatchInfo { pool.connection.use { it.prepareStatement("select `id` from `match` where find_in_set(?, players) AND end IS NULL") .use { prepared -> prepared.setString(0, player) val rs = prepared.executeQuery() if (!rs.next()) { - return -1 + return MatchInfo() } - return rs.getInt(1) + val id = rs.getInt(1) + return MatchManager.getMatchById(id) ?: throw IllegalStateException("Match Not Exist in db") } } } - fun recordMatch(type: String, players: List, start: Long = System.currentTimeMillis()) = + fun recordMatch(type: String, players: List, start: Long = System.currentTimeMillis()): Int = pool.connection.use { val prepared = it.prepareStatement( """ diff --git a/parent/src/main/kotlin/cc/maxmc/msm/parent/listener/PacketListener.kt b/parent/src/main/kotlin/cc/maxmc/msm/parent/listener/PacketListener.kt index aad0bc5..ee96101 100644 --- a/parent/src/main/kotlin/cc/maxmc/msm/parent/listener/PacketListener.kt +++ b/parent/src/main/kotlin/cc/maxmc/msm/parent/listener/PacketListener.kt @@ -53,10 +53,12 @@ object PacketListener : Listener { @EventHandler fun onChannelActive(evt: ChannelActiveEvent) { + log("§a| §7子BC ${evt.channel.remoteAddress()} 成功连接.") ChildManager.registerChild(evt.channel) } fun onChannelInactive(evt: ChannelInactiveEvent) { + log("§c| §7子BC ${evt.channel.remoteAddress()} 断开连接.") ChildManager.unregisterChild(evt.channel) } } \ No newline at end of file diff --git a/parent/src/main/kotlin/cc/maxmc/msm/parent/manager/ChildManager.kt b/parent/src/main/kotlin/cc/maxmc/msm/parent/manager/ChildManager.kt index 0db7529..91f1db5 100644 --- a/parent/src/main/kotlin/cc/maxmc/msm/parent/manager/ChildManager.kt +++ b/parent/src/main/kotlin/cc/maxmc/msm/parent/manager/ChildManager.kt @@ -20,10 +20,8 @@ object ChildManager { val packet = awaitPacket(PPacketChildInfo::class.java) { ch, _ -> ch == channel } - val child = ChildBungee(channel, packet.portRange) - + val child = ChildBungee(channel, packet.portRange, packet.types) children.add(child) - } } @@ -31,8 +29,8 @@ object ChildManager { children.removeIf { it.channel == channel } } - fun requestChild(): ChildBungee { - return children.filter { it.getAvailablePorts().isNotEmpty() }.maxByOrNull { it.getAvailablePorts().size } - ?: throw IllegalStateException("当前无可用端口开启新服务器.") + fun requestChild(type: String): ChildBungee { + return children.filter { it.getAvailablePorts().isNotEmpty() && it.types.contains(type) } + .maxByOrNull { it.getAvailablePorts().size } ?: throw IllegalStateException("当前无可用端口开启新服务器.") } } \ No newline at end of file diff --git a/parent/src/main/kotlin/cc/maxmc/msm/parent/manager/MatchManager.kt b/parent/src/main/kotlin/cc/maxmc/msm/parent/manager/MatchManager.kt new file mode 100644 index 0000000..587e55d --- /dev/null +++ b/parent/src/main/kotlin/cc/maxmc/msm/parent/manager/MatchManager.kt @@ -0,0 +1,27 @@ +package cc.maxmc.msm.parent.manager + +import cc.maxmc.msm.api.misc.MatchInfo +import cc.maxmc.msm.parent.database.SQLDatabase +import java.util.concurrent.ConcurrentHashMap + +object MatchManager { + private val matchMap = ConcurrentHashMap() + + fun requestMatch(type: String, players: List): MatchInfo { + val server = ServerManager.consumeServer(type) + val id = SQLDatabase.recordMatch(type, players) + val match = MatchInfo(id, server) + matchMap[id] = match + return match + } + + fun getMatchById(id: Int): MatchInfo? { + return matchMap[id] + } + + fun endMatch(id: Int) { + val match = getMatchById(id) ?: throw IllegalStateException("Match does not exist.") + ServerManager.endServer(match.server.uid) + SQLDatabase.endMatch(id) + } +} \ No newline at end of file diff --git a/parent/src/main/kotlin/cc/maxmc/msm/parent/manager/ServerManager.kt b/parent/src/main/kotlin/cc/maxmc/msm/parent/manager/ServerManager.kt index b58d4c8..1ac3061 100644 --- a/parent/src/main/kotlin/cc/maxmc/msm/parent/manager/ServerManager.kt +++ b/parent/src/main/kotlin/cc/maxmc/msm/parent/manager/ServerManager.kt @@ -1,17 +1,50 @@ package cc.maxmc.msm.parent.manager import cc.maxmc.msm.api.misc.ServerInfo +import cc.maxmc.msm.common.utils.log +import cc.maxmc.msm.common.utils.pluginScope +import kotlinx.coroutines.launch +import java.util.* import java.util.concurrent.ConcurrentHashMap object ServerManager { - val serverMap = ConcurrentHashMap>() + private val serverMap = ConcurrentHashMap>() - fun getAvailableServers(type: String): List { + fun consumeServer(type: String): ServerInfo { + val servers = getAvailableServers(type) + val info = servers.first() + info.isAvailable = false + if (servers.size - 1 <= 2) { + pluginScope.launch { + log("§b| §7剩余 $type 服务器不足,正在启动新服务端。") + val server = requireServer(type) + log("§b| §7类型 $type 服务器启动成功: ${server.server}") + } + } + return info + } + + fun endServer(uid: UUID) { + var result: ServerInfo? = null + val list = serverMap.values.find { + it.find { server -> server.uid == uid }?.let { server -> result = server; true } ?: false + } ?: throw IllegalStateException("Illegal state.") + list.remove(result) + } + + fun getServerById(uid: UUID): ServerInfo? { + return serverMap.flatMap { it.value }.find { it.uid == uid } + } + + private fun getAvailableServers(type: String): List { return serverMap[type]!!.filter { it.isAvailable } } - private fun requireServer(type: String) { - val child = ChildManager.requestChild() - + private suspend fun requireServer(type: String): ServerInfo { + val child = ChildManager.requestChild(type) + val list = serverMap.getOrPut(type) { ArrayList() } + val server = child.requestServer(type) + list.add(server) + return server } } \ No newline at end of file diff --git a/parent/src/main/kotlin/cc/maxmc/msm/parent/misc/ChildBungee.kt b/parent/src/main/kotlin/cc/maxmc/msm/parent/misc/ChildBungee.kt index d49f5ac..6f41375 100644 --- a/parent/src/main/kotlin/cc/maxmc/msm/parent/misc/ChildBungee.kt +++ b/parent/src/main/kotlin/cc/maxmc/msm/parent/misc/ChildBungee.kt @@ -1,18 +1,33 @@ package cc.maxmc.msm.parent.misc +import cc.maxmc.msm.api.misc.ServerInfo import cc.maxmc.msm.common.network.BungeePacket import cc.maxmc.msm.common.network.packet.CPacketRequestServer +import cc.maxmc.msm.common.network.packet.PPacketServerStarted import cc.maxmc.msm.common.utils.awaitPacket import io.netty.channel.Channel +import java.net.InetSocketAddress +import java.util.* -class ChildBungee(val channel: Channel, var ports: Set, var usedPorts: MutableSet = HashSet()) { +class ChildBungee( + val channel: Channel, val ports: Set, val types: Set, val usedPorts: MutableSet = HashSet() +) { private fun sendPacket(packet: BungeePacket) { channel.writeAndFlush(packet) } - suspend fun requestServer(type: String) { - sendPacket(CPacketRequestServer(type)) - awaitPacket() + suspend fun requestServer(type: String): ServerInfo { + val uid = UUID.randomUUID() + val server = ServerInfo( + uid, + "${(channel.remoteAddress() as InetSocketAddress).hostString}:${getAvailablePorts().first()}" + ) + val cPacket = CPacketRequestServer(type, server) + sendPacket(cPacket) + val packet = awaitPacket(PPacketServerStarted::class.java) { ch, packet -> + ch == channel && packet.serverInfo == server + } + return packet.serverInfo } fun getAvailablePorts() = ports - usedPorts diff --git a/parent/src/main/kotlin/cc/maxmc/msm/parent/netty/NetManager.kt b/parent/src/main/kotlin/cc/maxmc/msm/parent/netty/NetManager.kt index cc00319..2c04719 100644 --- a/parent/src/main/kotlin/cc/maxmc/msm/parent/netty/NetManager.kt +++ b/parent/src/main/kotlin/cc/maxmc/msm/parent/netty/NetManager.kt @@ -3,6 +3,8 @@ package cc.maxmc.msm.parent.netty import cc.maxmc.msm.common.network.netty.NetworkRegistry import cc.maxmc.msm.common.utils.log import cc.maxmc.msm.common.utils.pipelineInit +import cc.maxmc.msm.parent.manager.MatchManager +import cc.maxmc.msm.parent.manager.ServerManager import cc.maxmc.msm.parent.settings.Settings import io.netty.bootstrap.ServerBootstrap import io.netty.channel.ChannelFutureListener @@ -14,11 +16,8 @@ object NetManager { private val childGroup = NioEventLoopGroup() fun startServer() { - ServerBootstrap() - .channel(NioServerSocketChannel::class.java) - .group(parentGroup, childGroup) - .childHandler(pipelineInit(NetworkRegistry.PacketDirection.PARENT_BOUND)) - .bind(Settings.serverPort) + ServerBootstrap().channel(NioServerSocketChannel::class.java).group(parentGroup, childGroup) + .childHandler(pipelineInit(NetworkRegistry.PacketDirection.PARENT_BOUND)).bind(Settings.serverPort) .addListener(ChannelFutureListener { val result = it.cause() ?: return@ChannelFutureListener log( "§a| §7集群主服务端启动成功. ${ @@ -33,5 +32,4 @@ object NetManager { parentGroup.shutdownGracefully().sync() childGroup.shutdownGracefully().sync() } - } \ No newline at end of file diff --git a/parent/src/main/kotlin/cc/maxmc/msm/parent/settings/Settings.kt b/parent/src/main/kotlin/cc/maxmc/msm/parent/settings/Settings.kt index b3be27a..9b2199a 100644 --- a/parent/src/main/kotlin/cc/maxmc/msm/parent/settings/Settings.kt +++ b/parent/src/main/kotlin/cc/maxmc/msm/parent/settings/Settings.kt @@ -4,7 +4,7 @@ import cc.maxmc.msm.parent.settings.SettingsReader.config object Settings { val serverPort - get() = config.getInt("server_port", 25566) + get() = config.getInt("manage_port", 23333) object Database { val address: String diff --git a/parent/src/main/resources/settings.yml b/parent/src/main/resources/settings.yml index 133a1df..2595f3a 100644 --- a/parent/src/main/resources/settings.yml +++ b/parent/src/main/resources/settings.yml @@ -1,4 +1,7 @@ -serverPort: 12345 +# 子BC连接主BC的端口 +managePort: 23333 + +# 数据库配置 database: address: 127.0.0.1 port: 3306