Sync
This commit is contained in:
parent
c534b9508b
commit
31109849fe
|
|
@ -109,4 +109,6 @@ api.getServer("default", players);
|
||||||
|
|
||||||
A: 只提供服务器并记录玩家
|
A: 只提供服务器并记录玩家
|
||||||
|
|
||||||
4. Q: 服务端是
|
4. Q: 服务端启动方式
|
||||||
|
|
||||||
|
A: 启动脚本,参数为端口+自定义参数
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package cc.maxmc.msm.api;
|
package cc.maxmc.msm.api;
|
||||||
|
|
||||||
import cc.maxmc.msm.api.misc.ServerInfo;
|
import cc.maxmc.msm.api.misc.MatchInfo;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -9,12 +8,12 @@ import java.util.List;
|
||||||
@SuppressWarnings("unused") // API
|
@SuppressWarnings("unused") // API
|
||||||
public interface MultiServerManAPI {
|
public interface MultiServerManAPI {
|
||||||
@NotNull
|
@NotNull
|
||||||
ServerInfo getServer(@NotNull String type, @NotNull List<String> players);
|
MatchInfo getServer(@NotNull String type, @NotNull List<String> players);
|
||||||
|
|
||||||
void informEnd(int id);
|
void informEnd(int id);
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
ServerInfo getPlayerServer(@NotNull String player);
|
MatchInfo getPlayerServer(@NotNull String player);
|
||||||
|
|
||||||
Boolean containPlayer(@NotNull String player);
|
Boolean containPlayer(@NotNull String player);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,15 +1,34 @@
|
||||||
package cc.maxmc.msm.api.misc;
|
package cc.maxmc.msm.api.misc;
|
||||||
|
|
||||||
import com.google.common.net.HostAndPort;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
@SuppressWarnings("unused") // API
|
@SuppressWarnings("unused") // API
|
||||||
public class ServerInfo {
|
public class ServerInfo {
|
||||||
|
@NotNull
|
||||||
|
private final UUID uid;
|
||||||
@Nullable
|
@Nullable
|
||||||
private final HostAndPort server;
|
private final String server;
|
||||||
private final int id;
|
|
||||||
private boolean available;
|
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() {
|
public boolean isAvailable() {
|
||||||
return available;
|
return available;
|
||||||
}
|
}
|
||||||
|
|
@ -18,22 +37,21 @@ public class ServerInfo {
|
||||||
this.available = available;
|
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
|
@Nullable
|
||||||
public HostAndPort getServer() {
|
public String getServer() {
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getId() {
|
@Override
|
||||||
return id;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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()
|
|
||||||
}
|
|
||||||
|
|
@ -2,9 +2,10 @@ package cc.maxmc.msm.child
|
||||||
|
|
||||||
import cc.maxmc.msm.api.MultiServerManAPIProvider
|
import cc.maxmc.msm.api.MultiServerManAPIProvider
|
||||||
import cc.maxmc.msm.child.api.APIImpl
|
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.Api
|
||||||
import cc.maxmc.msm.child.command.Send
|
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.netty.NetClient
|
||||||
import cc.maxmc.msm.child.settings.Settings
|
import cc.maxmc.msm.child.settings.Settings
|
||||||
import cc.maxmc.msm.common.network.netty.NetworkRegistry
|
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, Send)
|
||||||
ProxyServer.getInstance().pluginManager.registerCommand(this, Api)
|
ProxyServer.getInstance().pluginManager.registerCommand(this, Api)
|
||||||
ProxyServer.getInstance().pluginManager.registerListener(this, APIPacketListener)
|
ProxyServer.getInstance().pluginManager.registerListener(this, APIPacketListener)
|
||||||
|
ProxyServer.getInstance().pluginManager.registerListener(this, ProtocolListener)
|
||||||
NetworkRegistry
|
NetworkRegistry
|
||||||
NetClient.start(Settings.Parent.address, Settings.Parent.port)
|
NetClient.init(Settings.Parent.address, Settings.Parent.port)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDisable() {
|
override fun onDisable() {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package cc.maxmc.msm.child.api
|
package cc.maxmc.msm.child.api
|
||||||
|
|
||||||
import cc.maxmc.msm.api.MultiServerManAPI
|
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.child.netty.NetClient
|
||||||
import cc.maxmc.msm.common.network.packet.PPacketAPICall
|
import cc.maxmc.msm.common.network.packet.PPacketAPICall
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
@ -13,10 +13,10 @@ object APIImpl : MultiServerManAPI {
|
||||||
val apiCallCache = HashMap<UUID, CompletableFuture<in Any>>()
|
val apiCallCache = HashMap<UUID, CompletableFuture<in Any>>()
|
||||||
private const val TIMEOUT = 3L
|
private const val TIMEOUT = 3L
|
||||||
|
|
||||||
override fun getServer(type: String, players: MutableList<String>): ServerInfo {
|
override fun getServer(type: String, players: MutableList<String>): MatchInfo {
|
||||||
val packet = PPacketAPICall.PPacketCallGetServer(type, players)
|
val packet = PPacketAPICall.PPacketCallGetServer(type, players)
|
||||||
NetClient.sendPacket(packet)
|
NetClient.sendPacket(packet)
|
||||||
val future = CompletableFuture<ServerInfo>()
|
val future = CompletableFuture<MatchInfo>()
|
||||||
apiCallCache[packet.uid] = future as CompletableFuture<Any>
|
apiCallCache[packet.uid] = future as CompletableFuture<Any>
|
||||||
return future.get(TIMEOUT, TimeUnit.SECONDS)
|
return future.get(TIMEOUT, TimeUnit.SECONDS)
|
||||||
}
|
}
|
||||||
|
|
@ -30,10 +30,10 @@ object APIImpl : MultiServerManAPI {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getPlayerServer(player: String): ServerInfo {
|
override fun getPlayerServer(player: String): MatchInfo {
|
||||||
val packet = PPacketAPICall.PPacketCallGetPlayerServer(player)
|
val packet = PPacketAPICall.PPacketCallGetPlayerServer(player)
|
||||||
NetClient.sendPacket(packet)
|
NetClient.sendPacket(packet)
|
||||||
val future = CompletableFuture<ServerInfo>()
|
val future = CompletableFuture<MatchInfo>()
|
||||||
apiCallCache[packet.uid] = future as CompletableFuture<Any>
|
apiCallCache[packet.uid] = future as CompletableFuture<Any>
|
||||||
return future.get(TIMEOUT, TimeUnit.SECONDS)
|
return future.get(TIMEOUT, TimeUnit.SECONDS)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.event.PacketReceiveEvent
|
||||||
import cc.maxmc.msm.common.network.packet.CPacketAPICallback
|
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.api.plugin.Listener
|
||||||
import net.md_5.bungee.event.EventHandler
|
import net.md_5.bungee.event.EventHandler
|
||||||
|
|
||||||
|
|
@ -21,12 +21,12 @@ object APIPacketListener : Listener {
|
||||||
}
|
}
|
||||||
|
|
||||||
is CPacketAPICallback.CPacketCallbackGetPlayerServer -> {
|
is CPacketAPICallback.CPacketCallbackGetPlayerServer -> {
|
||||||
future?.complete(packet.serverInfo)
|
future?.complete(packet.matchInfo)
|
||||||
?: throw IllegalStateException("Packet callback received, however no request")
|
?: throw IllegalStateException("Packet callback received, however no request")
|
||||||
}
|
}
|
||||||
|
|
||||||
is CPacketAPICallback.CPacketCallbackGetServer -> {
|
is CPacketAPICallback.CPacketCallbackGetServer -> {
|
||||||
future?.complete(packet.serverInfo)
|
future?.complete(packet.matchInfo)
|
||||||
?: throw IllegalStateException("Packet callback received, however no request")
|
?: throw IllegalStateException("Packet callback received, however no request")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -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<UUID, SubServer>()
|
||||||
|
|
||||||
|
@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.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -5,18 +5,19 @@ import cc.maxmc.msm.child.utils.ScriptRunner
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.nio.file.Path
|
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.copyToRecursively
|
||||||
import kotlin.io.path.createDirectories
|
import kotlin.io.path.createDirectories
|
||||||
import kotlin.io.path.deleteRecursively
|
import kotlin.io.path.deleteRecursively
|
||||||
|
|
||||||
@OptIn(kotlin.io.path.ExperimentalPathApi::class)
|
@OptIn(kotlin.io.path.ExperimentalPathApi::class)
|
||||||
class SubServer(
|
class SubServer(
|
||||||
val id: Int,
|
val uid: UUID, val type: String, val port: Int, baseFolder: Path = MultiServerMan.instance.dataFolder.toPath()
|
||||||
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 patternFolder = baseFolder.resolve("pattern").resolve(type).also { it.createDirectories() }
|
||||||
private val runner = ScriptRunner(serverFolder.resolve("start.sh"))
|
private val runner = ScriptRunner(serverFolder.resolve("start.sh"))
|
||||||
|
|
||||||
|
|
@ -24,16 +25,15 @@ class SubServer(
|
||||||
patternFolder.copyToRecursively(serverFolder, followLinks = false, overwrite = true)
|
patternFolder.copyToRecursively(serverFolder, followLinks = false, overwrite = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startServer() {
|
suspend fun startServer() = suspendCoroutine {
|
||||||
runner.launch(port.toString())
|
runner.launch(port.toString())
|
||||||
runner.onOutput("For help, type \"help\" or \"?\"") {
|
runner.onOutput("For help, type \"help\" or \"?\"") {
|
||||||
println("Started.")
|
it.resume(Unit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun cleanup() {
|
suspend fun cleanup() {
|
||||||
runner.exec("stop")
|
runner.exec("stop")
|
||||||
println("Exec stop")
|
|
||||||
runner.exit()
|
runner.exit()
|
||||||
serverFolder.deleteRecursively()
|
serverFolder.deleteRecursively()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,34 +2,45 @@ package cc.maxmc.msm.child.netty
|
||||||
|
|
||||||
import cc.maxmc.msm.common.network.BungeePacket
|
import cc.maxmc.msm.common.network.BungeePacket
|
||||||
import cc.maxmc.msm.common.network.netty.NetworkRegistry
|
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.pipelineInit
|
||||||
|
import cc.maxmc.msm.common.utils.pluginScope
|
||||||
import io.netty.bootstrap.Bootstrap
|
import io.netty.bootstrap.Bootstrap
|
||||||
import io.netty.channel.Channel
|
import io.netty.channel.Channel
|
||||||
import io.netty.channel.ChannelFutureListener
|
import io.netty.channel.ChannelFutureListener
|
||||||
import io.netty.channel.ChannelOption
|
import io.netty.channel.ChannelOption
|
||||||
import io.netty.channel.nio.NioEventLoopGroup
|
import io.netty.channel.nio.NioEventLoopGroup
|
||||||
import io.netty.channel.socket.nio.NioSocketChannel
|
import io.netty.channel.socket.nio.NioSocketChannel
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
|
||||||
object NetClient {
|
object NetClient {
|
||||||
private val loop = NioEventLoopGroup()
|
private val loop = NioEventLoopGroup()
|
||||||
private lateinit var channel: Channel
|
private lateinit var channel: Channel
|
||||||
|
private lateinit var boot: Bootstrap
|
||||||
|
|
||||||
fun start(address: String, port: Int) {
|
fun init(address: String, port: Int) {
|
||||||
val future = Bootstrap()
|
boot = Bootstrap().channel(NioSocketChannel::class.java).group(loop)
|
||||||
.channel(NioSocketChannel::class.java)
|
.handler(pipelineInit(NetworkRegistry.PacketDirection.CHILD_BOUND)).option(ChannelOption.TCP_NODELAY, true)
|
||||||
.group(loop)
|
|
||||||
.handler(pipelineInit(NetworkRegistry.PacketDirection.CHILD_BOUND))
|
|
||||||
.option(ChannelOption.TCP_NODELAY, true)
|
|
||||||
.remoteAddress(address, port)
|
.remoteAddress(address, port)
|
||||||
.connect().addListener(ChannelFutureListener {
|
runBlocking {
|
||||||
val result = it.cause() ?: return@ChannelFutureListener println(
|
connect(0)
|
||||||
"§a| §7成功连接到集群的主节点. (${
|
}
|
||||||
it.channel().remoteAddress()
|
}
|
||||||
})"
|
|
||||||
)
|
private suspend fun connect(delay: Long = 3000) {
|
||||||
result.printStackTrace()
|
delay(delay)
|
||||||
})
|
log("§b| §7正在尝试连接主BC")
|
||||||
channel = future.channel()
|
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) {
|
fun sendPacket(packet: BungeePacket) {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,14 @@
|
||||||
|
# 主BC的地址及端口
|
||||||
parent:
|
parent:
|
||||||
address: 127.0.0.1
|
address: 127.0.0.1
|
||||||
port: 23333
|
port: 23333
|
||||||
|
|
||||||
|
# 该子BC所在机器所能开放的端口
|
||||||
ports:
|
ports:
|
||||||
- 30000
|
- 30000
|
||||||
- 30001..30019
|
- 30001..30019
|
||||||
- 30443
|
|
||||||
|
# 该子BC所支持的服务端模版类型及模版类型启动所需参数
|
||||||
|
patterns:
|
||||||
|
main:
|
||||||
|
args: [ "-ListenPort=${port}", "-usr=usr", "-pwd=pwd" ]
|
||||||
|
|
@ -1,11 +1,7 @@
|
||||||
package cc.maxmc.msm.common.network.netty
|
package cc.maxmc.msm.common.network.netty
|
||||||
|
|
||||||
import cc.maxmc.msm.common.network.BungeePacket
|
import cc.maxmc.msm.common.network.BungeePacket
|
||||||
import cc.maxmc.msm.common.network.packet.CPacketAPICallback
|
import cc.maxmc.msm.common.network.packet.*
|
||||||
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 com.google.common.collect.HashBiMap
|
import com.google.common.collect.HashBiMap
|
||||||
|
|
||||||
object NetworkRegistry {
|
object NetworkRegistry {
|
||||||
|
|
@ -18,11 +14,16 @@ object NetworkRegistry {
|
||||||
registerPacket(PacketDirection.PARENT_BOUND, PPacketAPICall.PPacketCallContainPlayer::class.java)
|
registerPacket(PacketDirection.PARENT_BOUND, PPacketAPICall.PPacketCallContainPlayer::class.java)
|
||||||
registerPacket(PacketDirection.PARENT_BOUND, PPacketAPICall.PPacketCallInformEnd::class.java)
|
registerPacket(PacketDirection.PARENT_BOUND, PPacketAPICall.PPacketCallInformEnd::class.java)
|
||||||
registerPacket(PacketDirection.PARENT_BOUND, PPacketAPICall.PPacketCallGetServer::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, CPacketDebug::class.java)
|
||||||
registerPacket(PacketDirection.CHILD_BOUND, CPacketAPICallback.CPacketCallbackGetPlayerServer::class.java)
|
registerPacket(PacketDirection.CHILD_BOUND, CPacketAPICallback.CPacketCallbackGetPlayerServer::class.java)
|
||||||
registerPacket(PacketDirection.CHILD_BOUND, CPacketAPICallback.CPacketCallbackContainPlayer::class.java)
|
registerPacket(PacketDirection.CHILD_BOUND, CPacketAPICallback.CPacketCallbackContainPlayer::class.java)
|
||||||
registerPacket(PacketDirection.CHILD_BOUND, CPacketAPICallback.CPacketCallbackInformEnd::class.java)
|
registerPacket(PacketDirection.CHILD_BOUND, CPacketAPICallback.CPacketCallbackInformEnd::class.java)
|
||||||
registerPacket(PacketDirection.CHILD_BOUND, CPacketAPICallback.CPacketCallbackGetServer::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<out BungeePacket>) {
|
private fun registerPacket(direction: PacketDirection, packet: Class<out BungeePacket>) {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
package cc.maxmc.msm.common.network.packet
|
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.network.BungeePacket
|
||||||
import cc.maxmc.msm.common.utils.readServerInfo
|
import cc.maxmc.msm.common.utils.readMatchInfo
|
||||||
import cc.maxmc.msm.common.utils.writeServerInfo
|
import cc.maxmc.msm.common.utils.writeMatchInfo
|
||||||
import io.netty.buffer.ByteBuf
|
import io.netty.buffer.ByteBuf
|
||||||
import net.md_5.bungee.protocol.DefinedPacket
|
import net.md_5.bungee.protocol.DefinedPacket
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
@ -20,17 +20,16 @@ sealed class CPacketAPICallback(
|
||||||
}
|
}
|
||||||
|
|
||||||
class CPacketCallbackGetServer(
|
class CPacketCallbackGetServer(
|
||||||
var serverInfo: ServerInfo = ServerInfo(),
|
var matchInfo: MatchInfo = MatchInfo(), uid: UUID = UUID.randomUUID()
|
||||||
uid: UUID = UUID.randomUUID()
|
|
||||||
) : CPacketAPICallback(uid = uid) {
|
) : CPacketAPICallback(uid = uid) {
|
||||||
override fun encode(buf: ByteBuf) {
|
override fun encode(buf: ByteBuf) {
|
||||||
super.encode(buf)
|
super.encode(buf)
|
||||||
buf.writeServerInfo(serverInfo)
|
buf.writeMatchInfo(matchInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun decode(buf: ByteBuf) {
|
override fun decode(buf: ByteBuf) {
|
||||||
super.decode(buf)
|
super.decode(buf)
|
||||||
serverInfo = buf.readServerInfo()
|
matchInfo = buf.readMatchInfo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -39,23 +38,21 @@ sealed class CPacketAPICallback(
|
||||||
) : CPacketAPICallback(uid = uid)
|
) : CPacketAPICallback(uid = uid)
|
||||||
|
|
||||||
class CPacketCallbackGetPlayerServer(
|
class CPacketCallbackGetPlayerServer(
|
||||||
var serverInfo: ServerInfo,
|
var matchInfo: MatchInfo, uid: UUID = UUID.randomUUID()
|
||||||
uid: UUID = UUID.randomUUID()
|
|
||||||
) : CPacketAPICallback(uid = uid) {
|
) : CPacketAPICallback(uid = uid) {
|
||||||
override fun encode(buf: ByteBuf) {
|
override fun encode(buf: ByteBuf) {
|
||||||
super.encode(buf)
|
super.encode(buf)
|
||||||
buf.writeServerInfo(serverInfo)
|
buf.writeMatchInfo(matchInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun decode(buf: ByteBuf) {
|
override fun decode(buf: ByteBuf) {
|
||||||
super.decode(buf)
|
super.decode(buf)
|
||||||
serverInfo = buf.readServerInfo()
|
matchInfo = buf.readMatchInfo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CPacketCallbackContainPlayer(
|
class CPacketCallbackContainPlayer(
|
||||||
var value: Boolean,
|
var value: Boolean, uid: UUID = UUID.randomUUID()
|
||||||
uid: UUID = UUID.randomUUID()
|
|
||||||
) : CPacketAPICallback(uid = uid) {
|
) : CPacketAPICallback(uid = uid) {
|
||||||
override fun encode(buf: ByteBuf) {
|
override fun encode(buf: ByteBuf) {
|
||||||
super.encode(buf)
|
super.encode(buf)
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,23 @@
|
||||||
package cc.maxmc.msm.common.network.packet
|
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.network.BungeePacket
|
||||||
|
import cc.maxmc.msm.common.utils.readServerInfo
|
||||||
|
import cc.maxmc.msm.common.utils.writeServerInfo
|
||||||
import io.netty.buffer.ByteBuf
|
import io.netty.buffer.ByteBuf
|
||||||
import net.md_5.bungee.protocol.DefinedPacket
|
import net.md_5.bungee.protocol.DefinedPacket
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class CPacketRequestServer(
|
class CPacketRequestServer(
|
||||||
var type: String,
|
var type: String = "",
|
||||||
var uid: UUID = UUID.randomUUID()
|
var serverInfo: ServerInfo = ServerInfo(),
|
||||||
) : BungeePacket() {
|
) : BungeePacket() {
|
||||||
override fun encode(buf: ByteBuf) {
|
override fun encode(buf: ByteBuf) {
|
||||||
DefinedPacket.writeUUID(uid, buf)
|
|
||||||
DefinedPacket.writeString(type, buf)
|
DefinedPacket.writeString(type, buf)
|
||||||
|
buf.writeServerInfo(serverInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun decode(buf: ByteBuf) {
|
override fun decode(buf: ByteBuf) {
|
||||||
uid = DefinedPacket.readUUID(buf)
|
|
||||||
type = DefinedPacket.readString(buf)
|
type = DefinedPacket.readString(buf)
|
||||||
|
serverInfo = buf.readServerInfo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,7 +4,8 @@ import cc.maxmc.msm.common.network.BungeePacket
|
||||||
import io.netty.buffer.ByteBuf
|
import io.netty.buffer.ByteBuf
|
||||||
import net.md_5.bungee.protocol.DefinedPacket
|
import net.md_5.bungee.protocol.DefinedPacket
|
||||||
|
|
||||||
class PPacketChildInfo(var portRange: MutableSet<Int> = HashSet(), var types: MutableSet<String>) : BungeePacket() {
|
class PPacketChildInfo(var portRange: MutableSet<Int> = HashSet(), var types: MutableSet<String> = HashSet()) :
|
||||||
|
BungeePacket() {
|
||||||
override fun encode(buf: ByteBuf) {
|
override fun encode(buf: ByteBuf) {
|
||||||
DefinedPacket.writeVarInt(portRange.size, buf)
|
DefinedPacket.writeVarInt(portRange.size, buf)
|
||||||
portRange.forEach {
|
portRange.forEach {
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
package cc.maxmc.msm.common.utils
|
package cc.maxmc.msm.common.utils
|
||||||
|
|
||||||
|
import cc.maxmc.msm.api.misc.MatchInfo
|
||||||
import cc.maxmc.msm.api.misc.ServerInfo
|
import cc.maxmc.msm.api.misc.ServerInfo
|
||||||
import cc.maxmc.msm.common.network.ClusterPacketHandler
|
import cc.maxmc.msm.common.network.ClusterPacketHandler
|
||||||
import cc.maxmc.msm.common.network.netty.ClusterMsgCodec
|
import cc.maxmc.msm.common.network.netty.ClusterMsgCodec
|
||||||
import cc.maxmc.msm.common.network.netty.NetworkRegistry
|
import cc.maxmc.msm.common.network.netty.NetworkRegistry
|
||||||
import com.google.common.net.HostAndPort
|
|
||||||
import io.netty.buffer.ByteBuf
|
import io.netty.buffer.ByteBuf
|
||||||
import io.netty.channel.Channel
|
import io.netty.channel.Channel
|
||||||
import io.netty.channel.ChannelInitializer
|
import io.netty.channel.ChannelInitializer
|
||||||
|
|
@ -27,15 +27,25 @@ fun pipelineInit(direction: NetworkRegistry.PacketDirection) = channelInit<Socke
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ByteBuf.writeServerInfo(info: ServerInfo) {
|
fun ByteBuf.writeServerInfo(info: ServerInfo) {
|
||||||
|
DefinedPacket.writeUUID(info.uid, this)
|
||||||
DefinedPacket.writeString(info.server.toString(), this)
|
DefinedPacket.writeString(info.server.toString(), this)
|
||||||
DefinedPacket.writeVarInt(info.id, this)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ByteBuf.readServerInfo(): ServerInfo {
|
fun ByteBuf.readServerInfo(): ServerInfo {
|
||||||
|
val uid = DefinedPacket.readUUID(this)
|
||||||
val hap = DefinedPacket.readString(this)
|
val hap = DefinedPacket.readString(this)
|
||||||
val id = DefinedPacket.readVarInt(this)
|
|
||||||
return ServerInfo(
|
return ServerInfo(
|
||||||
HostAndPort.fromString(hap),
|
uid, hap
|
||||||
id
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ByteBuf.writeMatchInfo(match: MatchInfo) {
|
||||||
|
DefinedPacket.writeVarInt(match.id, this)
|
||||||
|
writeServerInfo(match.server)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ByteBuf.readMatchInfo(): MatchInfo {
|
||||||
|
val id = DefinedPacket.readVarInt(this)
|
||||||
|
val server = readServerInfo()
|
||||||
|
return MatchInfo(id, server)
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,8 @@ package cc.maxmc.msm.parent
|
||||||
import cc.maxmc.msm.api.MultiServerManAPIProvider
|
import cc.maxmc.msm.api.MultiServerManAPIProvider
|
||||||
import cc.maxmc.msm.parent.api.APIImpl
|
import cc.maxmc.msm.parent.api.APIImpl
|
||||||
import cc.maxmc.msm.parent.listener.PacketListener
|
import cc.maxmc.msm.parent.listener.PacketListener
|
||||||
|
import cc.maxmc.msm.parent.manager.MatchManager
|
||||||
|
import cc.maxmc.msm.parent.manager.ServerManager
|
||||||
import cc.maxmc.msm.parent.netty.NetManager
|
import cc.maxmc.msm.parent.netty.NetManager
|
||||||
import net.md_5.bungee.api.ProxyServer
|
import net.md_5.bungee.api.ProxyServer
|
||||||
import net.md_5.bungee.api.plugin.Plugin
|
import net.md_5.bungee.api.plugin.Plugin
|
||||||
|
|
@ -14,6 +16,8 @@ class MultiServerMan : Plugin() {
|
||||||
MultiServerManAPIProvider.register(APIImpl)
|
MultiServerManAPIProvider.register(APIImpl)
|
||||||
ProxyServer.getInstance().pluginManager.registerListener(this, PacketListener)
|
ProxyServer.getInstance().pluginManager.registerListener(this, PacketListener)
|
||||||
NetManager.startServer()
|
NetManager.startServer()
|
||||||
|
ServerManager
|
||||||
|
MatchManager
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDisable() {
|
override fun onDisable() {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
package cc.maxmc.msm.parent
|
|
||||||
|
|
||||||
import sun.misc.Signal
|
|
||||||
import java.lang.management.ManagementFactory
|
|
||||||
import kotlin.system.exitProcess
|
|
||||||
|
|
||||||
fun main() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +1,24 @@
|
||||||
package cc.maxmc.msm.parent.api
|
package cc.maxmc.msm.parent.api
|
||||||
|
|
||||||
import cc.maxmc.msm.api.MultiServerManAPI
|
import cc.maxmc.msm.api.MultiServerManAPI
|
||||||
import cc.maxmc.msm.api.misc.ServerInfo
|
import cc.maxmc.msm.api.misc.MatchInfo
|
||||||
import com.google.common.net.HostAndPort
|
import cc.maxmc.msm.parent.database.SQLDatabase
|
||||||
|
import cc.maxmc.msm.parent.manager.MatchManager
|
||||||
|
|
||||||
object APIImpl : MultiServerManAPI {
|
object APIImpl : MultiServerManAPI {
|
||||||
override fun getServer(type: String, players: MutableList<String>): ServerInfo {
|
override fun getServer(type: String, players: List<String>): MatchInfo {
|
||||||
TODO("not implemented")
|
return MatchManager.requestMatch(type, players)
|
||||||
return ServerInfo(HostAndPort.fromString("127.0.0.1:23456"), 1024)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun informEnd(id: Int) {
|
override fun informEnd(id: Int) {
|
||||||
TODO("not implemented")
|
MatchManager.endMatch(id)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getPlayerServer(player: String): ServerInfo {
|
override fun getPlayerServer(player: String): MatchInfo {
|
||||||
TODO("not implemented")
|
return SQLDatabase.getPlayerMatch(player)
|
||||||
return ServerInfo(HostAndPort.fromString("127.0.0.1:34567"), 1025)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun containPlayer(player: String): Boolean {
|
override fun containPlayer(player: String): Boolean {
|
||||||
TODO("not implemented")
|
return getPlayerServer(player).id != -1
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
package cc.maxmc.msm.parent.database
|
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 cc.maxmc.msm.parent.settings.Settings
|
||||||
import com.zaxxer.hikari.HikariConfig
|
import com.zaxxer.hikari.HikariConfig
|
||||||
import com.zaxxer.hikari.pool.HikariPool
|
import com.zaxxer.hikari.pool.HikariPool
|
||||||
import java.sql.Timestamp
|
import java.sql.Timestamp
|
||||||
|
|
||||||
class SQLDatabase {
|
object SQLDatabase {
|
||||||
private val config = HikariConfig()
|
private val config = HikariConfig()
|
||||||
private lateinit var pool: HikariPool
|
private lateinit var pool: HikariPool
|
||||||
fun initDatabase() {
|
fun initDatabase() {
|
||||||
|
|
@ -36,21 +38,22 @@ class SQLDatabase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getPlayerMatch(player: String): Int {
|
fun getPlayerMatch(player: String): MatchInfo {
|
||||||
pool.connection.use {
|
pool.connection.use {
|
||||||
it.prepareStatement("select `id` from `match` where find_in_set(?, players) AND end IS NULL")
|
it.prepareStatement("select `id` from `match` where find_in_set(?, players) AND end IS NULL")
|
||||||
.use { prepared ->
|
.use { prepared ->
|
||||||
prepared.setString(0, player)
|
prepared.setString(0, player)
|
||||||
val rs = prepared.executeQuery()
|
val rs = prepared.executeQuery()
|
||||||
if (!rs.next()) {
|
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<String>, start: Long = System.currentTimeMillis()) =
|
fun recordMatch(type: String, players: List<String>, start: Long = System.currentTimeMillis()): Int =
|
||||||
pool.connection.use {
|
pool.connection.use {
|
||||||
val prepared = it.prepareStatement(
|
val prepared = it.prepareStatement(
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -53,10 +53,12 @@ object PacketListener : Listener {
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
fun onChannelActive(evt: ChannelActiveEvent) {
|
fun onChannelActive(evt: ChannelActiveEvent) {
|
||||||
|
log("§a| §7子BC ${evt.channel.remoteAddress()} 成功连接.")
|
||||||
ChildManager.registerChild(evt.channel)
|
ChildManager.registerChild(evt.channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onChannelInactive(evt: ChannelInactiveEvent) {
|
fun onChannelInactive(evt: ChannelInactiveEvent) {
|
||||||
|
log("§c| §7子BC ${evt.channel.remoteAddress()} 断开连接.")
|
||||||
ChildManager.unregisterChild(evt.channel)
|
ChildManager.unregisterChild(evt.channel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -20,10 +20,8 @@ object ChildManager {
|
||||||
val packet = awaitPacket(PPacketChildInfo::class.java) { ch, _ ->
|
val packet = awaitPacket(PPacketChildInfo::class.java) { ch, _ ->
|
||||||
ch == channel
|
ch == channel
|
||||||
}
|
}
|
||||||
val child = ChildBungee(channel, packet.portRange)
|
val child = ChildBungee(channel, packet.portRange, packet.types)
|
||||||
|
|
||||||
children.add(child)
|
children.add(child)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -31,8 +29,8 @@ object ChildManager {
|
||||||
children.removeIf { it.channel == channel }
|
children.removeIf { it.channel == channel }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun requestChild(): ChildBungee {
|
fun requestChild(type: String): ChildBungee {
|
||||||
return children.filter { it.getAvailablePorts().isNotEmpty() }.maxByOrNull { it.getAvailablePorts().size }
|
return children.filter { it.getAvailablePorts().isNotEmpty() && it.types.contains(type) }
|
||||||
?: throw IllegalStateException("当前无可用端口开启新服务器.")
|
.maxByOrNull { it.getAvailablePorts().size } ?: throw IllegalStateException("当前无可用端口开启新服务器.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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<Int, MatchInfo>()
|
||||||
|
|
||||||
|
fun requestMatch(type: String, players: List<String>): 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,17 +1,50 @@
|
||||||
package cc.maxmc.msm.parent.manager
|
package cc.maxmc.msm.parent.manager
|
||||||
|
|
||||||
import cc.maxmc.msm.api.misc.ServerInfo
|
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
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
object ServerManager {
|
object ServerManager {
|
||||||
val serverMap = ConcurrentHashMap<String, List<ServerInfo>>()
|
private val serverMap = ConcurrentHashMap<String, MutableList<ServerInfo>>()
|
||||||
|
|
||||||
fun getAvailableServers(type: String): List<ServerInfo> {
|
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<ServerInfo> {
|
||||||
return serverMap[type]!!.filter { it.isAvailable }
|
return serverMap[type]!!.filter { it.isAvailable }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun requireServer(type: String) {
|
private suspend fun requireServer(type: String): ServerInfo {
|
||||||
val child = ChildManager.requestChild()
|
val child = ChildManager.requestChild(type)
|
||||||
|
val list = serverMap.getOrPut(type) { ArrayList() }
|
||||||
|
val server = child.requestServer(type)
|
||||||
|
list.add(server)
|
||||||
|
return server
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,18 +1,33 @@
|
||||||
package cc.maxmc.msm.parent.misc
|
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.BungeePacket
|
||||||
import cc.maxmc.msm.common.network.packet.CPacketRequestServer
|
import cc.maxmc.msm.common.network.packet.CPacketRequestServer
|
||||||
|
import cc.maxmc.msm.common.network.packet.PPacketServerStarted
|
||||||
import cc.maxmc.msm.common.utils.awaitPacket
|
import cc.maxmc.msm.common.utils.awaitPacket
|
||||||
import io.netty.channel.Channel
|
import io.netty.channel.Channel
|
||||||
|
import java.net.InetSocketAddress
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
class ChildBungee(val channel: Channel, var ports: Set<Int>, var usedPorts: MutableSet<Int> = HashSet()) {
|
class ChildBungee(
|
||||||
|
val channel: Channel, val ports: Set<Int>, val types: Set<String>, val usedPorts: MutableSet<Int> = HashSet()
|
||||||
|
) {
|
||||||
private fun sendPacket(packet: BungeePacket) {
|
private fun sendPacket(packet: BungeePacket) {
|
||||||
channel.writeAndFlush(packet)
|
channel.writeAndFlush(packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun requestServer(type: String) {
|
suspend fun requestServer(type: String): ServerInfo {
|
||||||
sendPacket(CPacketRequestServer(type))
|
val uid = UUID.randomUUID()
|
||||||
awaitPacket()
|
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
|
fun getAvailablePorts() = ports - usedPorts
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ package cc.maxmc.msm.parent.netty
|
||||||
import cc.maxmc.msm.common.network.netty.NetworkRegistry
|
import cc.maxmc.msm.common.network.netty.NetworkRegistry
|
||||||
import cc.maxmc.msm.common.utils.log
|
import cc.maxmc.msm.common.utils.log
|
||||||
import cc.maxmc.msm.common.utils.pipelineInit
|
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 cc.maxmc.msm.parent.settings.Settings
|
||||||
import io.netty.bootstrap.ServerBootstrap
|
import io.netty.bootstrap.ServerBootstrap
|
||||||
import io.netty.channel.ChannelFutureListener
|
import io.netty.channel.ChannelFutureListener
|
||||||
|
|
@ -14,11 +16,8 @@ object NetManager {
|
||||||
private val childGroup = NioEventLoopGroup()
|
private val childGroup = NioEventLoopGroup()
|
||||||
|
|
||||||
fun startServer() {
|
fun startServer() {
|
||||||
ServerBootstrap()
|
ServerBootstrap().channel(NioServerSocketChannel::class.java).group(parentGroup, childGroup)
|
||||||
.channel(NioServerSocketChannel::class.java)
|
.childHandler(pipelineInit(NetworkRegistry.PacketDirection.PARENT_BOUND)).bind(Settings.serverPort)
|
||||||
.group(parentGroup, childGroup)
|
|
||||||
.childHandler(pipelineInit(NetworkRegistry.PacketDirection.PARENT_BOUND))
|
|
||||||
.bind(Settings.serverPort)
|
|
||||||
.addListener(ChannelFutureListener {
|
.addListener(ChannelFutureListener {
|
||||||
val result = it.cause() ?: return@ChannelFutureListener log(
|
val result = it.cause() ?: return@ChannelFutureListener log(
|
||||||
"§a| §7集群主服务端启动成功. ${
|
"§a| §7集群主服务端启动成功. ${
|
||||||
|
|
@ -33,5 +32,4 @@ object NetManager {
|
||||||
parentGroup.shutdownGracefully().sync()
|
parentGroup.shutdownGracefully().sync()
|
||||||
childGroup.shutdownGracefully().sync()
|
childGroup.shutdownGracefully().sync()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -4,7 +4,7 @@ import cc.maxmc.msm.parent.settings.SettingsReader.config
|
||||||
|
|
||||||
object Settings {
|
object Settings {
|
||||||
val serverPort
|
val serverPort
|
||||||
get() = config.getInt("server_port", 25566)
|
get() = config.getInt("manage_port", 23333)
|
||||||
|
|
||||||
object Database {
|
object Database {
|
||||||
val address: String
|
val address: String
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
serverPort: 12345
|
# 子BC连接主BC的端口
|
||||||
|
managePort: 23333
|
||||||
|
|
||||||
|
# 数据库配置
|
||||||
database:
|
database:
|
||||||
address: 127.0.0.1
|
address: 127.0.0.1
|
||||||
port: 3306
|
port: 3306
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue