parent
54ce760feb
commit
75dfd94e66
53
README.md
53
README.md
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
### `func getServer()`
|
### `func getServer()`
|
||||||
|
|
||||||
- 接口描述:获取一个可用的服务器ip,并记录该对局的参与玩家。
|
- 接口描述:提供模版类型,获取一个可用的服务器ip,并记录该对局的参与玩家。
|
||||||
|
|
||||||
- 返回值:
|
- 返回值:
|
||||||
|
|
||||||
|
|
@ -38,7 +38,8 @@
|
||||||
- Int类型的对局id
|
- Int类型的对局id
|
||||||
|
|
||||||
- 参数列表:
|
- 参数列表:
|
||||||
- `ArrayList<Player> players`
|
- `(List<Player> players)`
|
||||||
|
-
|
||||||
|
|
||||||
### `func informEnd()`
|
### `func informEnd()`
|
||||||
|
|
||||||
|
|
@ -47,7 +48,7 @@
|
||||||
- 返回值:无
|
- 返回值:无
|
||||||
|
|
||||||
- 参数列表:
|
- 参数列表:
|
||||||
- int id
|
- `(int id)`
|
||||||
|
|
||||||
### `func getPlayerServer()`
|
### `func getPlayerServer()`
|
||||||
|
|
||||||
|
|
@ -60,12 +61,52 @@
|
||||||
- 参数列表:
|
- 参数列表:
|
||||||
- `(Player player)`
|
- `(Player player)`
|
||||||
|
|
||||||
### `func containPlayer`
|
### `func containPlayer()`
|
||||||
|
|
||||||
- 接口描述:查询某个玩家是否在对局中。
|
- 接口描述:查询某个玩家是否在对局中。
|
||||||
|
|
||||||
- 返回值:
|
- 返回值:
|
||||||
- bool
|
- bool
|
||||||
|
|
||||||
- 参数列表:
|
- 参数列表:
|
||||||
- `(Player player)`
|
- `(Player player)`
|
||||||
|
|
||||||
|
## 数据库结构
|
||||||
|
|
||||||
|
- `match`
|
||||||
|
|
||||||
|
| id(int) | start(datetime) | end(datetime) | players(text) |
|
||||||
|
| ------- | --------------- | ------------- | ------------------------------------ |
|
||||||
|
| 1 | 1678554776 | 1678554784 | TONY_All,Sanseyooyea,PlayerA,PlayerB |
|
||||||
|
## API 使用
|
||||||
|
|
||||||
|
依赖:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
dependencies {
|
||||||
|
compileOnly("cc.maxmc.msm:MultiServerMan-API:${version}")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
使用:
|
||||||
|
|
||||||
|
```java
|
||||||
|
List<ProxyPlayer> players;
|
||||||
|
|
||||||
|
MultiServerManAPI api = MultiServerManAPIProvider.getAPI();
|
||||||
|
api.getServer("default", players);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Q&A
|
||||||
|
|
||||||
|
1. Q: 不同类型的服务端是怎么区分的
|
||||||
|
|
||||||
|
A: 每个子端保留多种模版
|
||||||
|
|
||||||
|
2. Q: 数据库类型
|
||||||
|
|
||||||
|
A: MySQL / MariaDB
|
||||||
|
|
||||||
|
3. Q: getServer是需要负责把玩家传到子服还是只是提供服务器并记录玩家
|
||||||
|
|
||||||
|
A: 只提供服务器并记录玩家
|
||||||
|
|
||||||
|
4. Q: 服务端是
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "cc.maxmc.msm.api"
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven("https://repo.papermc.io/repository/maven-public/")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib"))
|
||||||
|
@Suppress("VulnerableLibrariesLocal")
|
||||||
|
compileOnly("io.github.waterfallmc:waterfall-api:1.19-R0.1-SNAPSHOT")
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package cc.maxmc.msm.api;
|
||||||
|
|
||||||
|
import cc.maxmc.msm.api.misc.ServerInfo;
|
||||||
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused") // API
|
||||||
|
public interface MultiServerManAPI {
|
||||||
|
ServerInfo getServer(String type, List<ProxiedPlayer> players);
|
||||||
|
|
||||||
|
void informEnd(int id);
|
||||||
|
|
||||||
|
ServerInfo getPlayerServer(ProxiedPlayer player);
|
||||||
|
|
||||||
|
Boolean containPlayer(ProxiedPlayer player);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
package cc.maxmc.msm.api;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused") // API
|
||||||
|
public abstract class MultiServerManAPIProvider {
|
||||||
|
private static MultiServerManAPIProvider instance;
|
||||||
|
|
||||||
|
public static MultiServerManAPI getAPI() {
|
||||||
|
if (instance == null) {
|
||||||
|
throw new NotLoadedException();
|
||||||
|
}
|
||||||
|
return instance.provideAPI();
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract MultiServerManAPI provideAPI();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在加载 API 之前请求 API 时引发异常。
|
||||||
|
*/
|
||||||
|
private static final class NotLoadedException extends IllegalStateException {
|
||||||
|
private static final String MESSAGE = "The MultiServerMan API isn't loaded yet!\n" +
|
||||||
|
"This could be because:\n" +
|
||||||
|
" a) the MultiServerMan plugin is not installed or it failed to enable\n" +
|
||||||
|
" b) the plugin in the stacktrace does not declare a dependency on MultiServerMan\n" +
|
||||||
|
" c) the plugin in the stacktrace is retrieving the API before the plugin 'enable' phase\n" +
|
||||||
|
" (call the #get method in onEnable, not the constructor!)\n";
|
||||||
|
|
||||||
|
NotLoadedException() {
|
||||||
|
super(MESSAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
package cc.maxmc.msm.api.misc;
|
||||||
|
|
||||||
|
import com.google.common.net.HostAndPort;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused") // API
|
||||||
|
public class ServerInfo {
|
||||||
|
@Nullable
|
||||||
|
private final HostAndPort server;
|
||||||
|
private final int id;
|
||||||
|
|
||||||
|
public ServerInfo(@Nullable HostAndPort server, int id) {
|
||||||
|
this.server = server;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public HostAndPort getServer() {
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,27 +1,2 @@
|
||||||
plugins {
|
|
||||||
kotlin("jvm") version "1.8.0"
|
|
||||||
application
|
|
||||||
}
|
|
||||||
|
|
||||||
group = "cc.maxmc.msm"
|
group = "cc.maxmc.msm"
|
||||||
version = "1.0-SNAPSHOT"
|
version = "1.0-SNAPSHOT"
|
||||||
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
testImplementation(kotlin("test"))
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.test {
|
|
||||||
useJUnitPlatform()
|
|
||||||
}
|
|
||||||
|
|
||||||
kotlin {
|
|
||||||
jvmToolchain(8)
|
|
||||||
}
|
|
||||||
|
|
||||||
application {
|
|
||||||
mainClass.set("MainKt")
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "cc.maxmc.msm.child"
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven("https://repo.papermc.io/repository/maven-public/")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib"))
|
||||||
|
compileOnly("io.github.waterfallmc:waterfall-api:1.19-R0.1-SNAPSHOT")
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "cc.maxmc.msm.common"
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
mavenLocal()
|
||||||
|
maven("https://repo.papermc.io/repository/maven-public/")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib"))
|
||||||
|
compileOnly("io.github.waterfallmc:waterfall-api:1.19-R0.1-SNAPSHOT")
|
||||||
|
compileOnly("net.md-5:bungeecord-proxy:1.19-R0.1-SNAPSHOT") {
|
||||||
|
isTransitive = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
package cc.maxmc.msm.common
|
||||||
|
|
||||||
|
import cc.maxmc.msm.common.network.ClusterMsgCodec
|
||||||
|
import io.netty.channel.Channel
|
||||||
|
import net.md_5.bungee.BungeeCord
|
||||||
|
|
||||||
|
object PacketInjector {
|
||||||
|
private val bungee = BungeeCord.getInstance()
|
||||||
|
private val field = bungee::class.java.getDeclaredField("listeners").also {
|
||||||
|
it.isAccessible = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun inject() {
|
||||||
|
val channel = getChannel()
|
||||||
|
channel.pipeline().addFirst("ClusterMsgCodec", ClusterMsgCodec)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getChannel(): Channel {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
val channelList = field.get(bungee) as Collection<Channel>
|
||||||
|
while (true) {
|
||||||
|
return channelList.firstOrNull() ?: continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package cc.maxmc.msm.common.network
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf
|
||||||
|
|
||||||
|
interface BungeePacket: Cloneable {
|
||||||
|
fun encode(buf: ByteBuf)
|
||||||
|
|
||||||
|
fun decode(buf: ByteBuf)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package cc.maxmc.msm.common.network
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf
|
||||||
|
import io.netty.channel.ChannelHandlerContext
|
||||||
|
import io.netty.handler.codec.ByteToMessageCodec
|
||||||
|
|
||||||
|
object ClusterMsgCodec : ByteToMessageCodec<BungeePacket>() {
|
||||||
|
override fun encode(ctx: ChannelHandlerContext, msg: BungeePacket, out: ByteBuf) {
|
||||||
|
msg.encode(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun decode(ctx: ChannelHandlerContext, `in`: ByteBuf, out: MutableList<Any>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
package cc.maxmc.msm.common.network
|
||||||
|
|
||||||
|
import com.google.common.collect.HashBiMap
|
||||||
|
|
||||||
|
object NetworkRegistry {
|
||||||
|
val parentBoundMap = HashBiMap.create<Int, BungeePacket>()
|
||||||
|
val childBoundMap = HashBiMap.create<Int, BungeePacket>()
|
||||||
|
|
||||||
|
fun registerPacket(packet: BungeePacket, direction: PacketDirection) {
|
||||||
|
if (direction == PacketDirection.ParentBound) {
|
||||||
|
parentBoundMap
|
||||||
|
} else {
|
||||||
|
childBoundMap
|
||||||
|
}.let {
|
||||||
|
it[it.size] = packet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class PacketDirection {
|
||||||
|
ParentBound,
|
||||||
|
ChildBound;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
id("com.github.johnrengelman.shadow")
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "cc.maxmc.msm.parent"
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven("https://repo.papermc.io/repository/maven-public/")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib"))
|
||||||
|
implementation(project(":api"))
|
||||||
|
implementation(project(":common"))
|
||||||
|
@Suppress("VulnerableLibrariesLocal")
|
||||||
|
compileOnly("io.github.waterfallmc:waterfall-api:1.19-R0.1-SNAPSHOT")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.shadowJar {
|
||||||
|
relocate("kotlin", "cc.maxmc.msm.lib.kotlin")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.build {
|
||||||
|
dependsOn(tasks.shadowJar)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package cc.maxmc.msm.parent
|
||||||
|
|
||||||
|
import cc.maxmc.msm.common.PacketInjector
|
||||||
|
import net.md_5.bungee.api.ProxyServer
|
||||||
|
import net.md_5.bungee.api.plugin.Plugin
|
||||||
|
|
||||||
|
class MultiServerMan: Plugin() {
|
||||||
|
|
||||||
|
override fun onEnable() {
|
||||||
|
Thread.sleep(5000)
|
||||||
|
ProxyServer.getInstance().scheduler.runAsync(this) {
|
||||||
|
println("injecting")
|
||||||
|
PacketInjector.inject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDisable() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
name: MultiServerMan-Parent
|
||||||
|
main: cc.maxmc.msm.parent.MultiServerMan
|
||||||
|
author: TONY_All
|
||||||
|
|
@ -1,3 +1,9 @@
|
||||||
|
plugins {
|
||||||
|
id("com.github.johnrengelman.shadow") version "8.1.0" apply false
|
||||||
|
kotlin("jvm") version "1.8.10" apply false
|
||||||
|
}
|
||||||
|
|
||||||
rootProject.name = "MultiServerMan"
|
rootProject.name = "MultiServerMan"
|
||||||
|
|
||||||
|
include("common", "parent-side", "child-side")
|
||||||
|
include("api")
|
||||||
Loading…
Reference in New Issue