init structure

init protocol
This commit is contained in:
tony_all 2023-03-12 13:10:44 +08:00
parent 54ce760feb
commit 75dfd94e66
17 changed files with 303 additions and 34 deletions

View File

@ -29,7 +29,7 @@
### `func getServer()`
- 接口描述获取一个可用的服务器ip并记录该对局的参与玩家。
- 接口描述:提供模版类型,获取一个可用的服务器ip并记录该对局的参与玩家。
- 返回值:
@ -38,7 +38,8 @@
- Int类型的对局id
- 参数列表:
- `ArrayList<Player> players`
- `(List<Player> players)`
-
### `func informEnd()`
@ -47,7 +48,7 @@
- 返回值:无
- 参数列表:
- int id
- `(int id)`
### `func getPlayerServer()`
@ -60,12 +61,52 @@
- 参数列表:
- `(Player player)`
### `func containPlayer`
### `func containPlayer()`
- 接口描述:查询某个玩家是否在对局中。
- 返回值:
- 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: 服务端是

16
api/build.gradle.kts Normal file
View File

@ -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")
}

View File

@ -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);
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -1,27 +1,2 @@
plugins {
kotlin("jvm") version "1.8.0"
application
}
group = "cc.maxmc.msm"
version = "1.0-SNAPSHOT"
repositories {
mavenCentral()
}
dependencies {
testImplementation(kotlin("test"))
}
tasks.test {
useJUnitPlatform()
}
kotlin {
jvmToolchain(8)
}
application {
mainClass.set("MainKt")
}
version = "1.0-SNAPSHOT"

View File

@ -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")
}

19
common/build.gradle.kts Normal file
View File

@ -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
}
}

View File

@ -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
}
}
}

View File

@ -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)
}

View File

@ -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>) {
}
}

View File

@ -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;
}
}

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
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
zipStorePath=wrapper/dists

View File

@ -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)
}

View File

@ -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() {
}
}

View File

@ -0,0 +1,3 @@
name: MultiServerMan-Parent
main: cc.maxmc.msm.parent.MultiServerMan
author: TONY_All

View File

@ -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"
include("common", "parent-side", "child-side")
include("api")