mirror of
https://github.com/layue13/MoonBridge.git
synced 2026-10-26 19:03:49 +00:00
docs: consolidate Chinese documentation
This commit is contained in:
1 parent
9fa6a782a6
commit
8063f6eb1f
25 files changed
+151
-852
No files matched your search
@@ -1,14 +1,157 @@
|
||||
# StrataProxy
|
||||
|
||||
StrataProxy 是 Java 25 Minecraft 后端代理。它负责连接接入、后端路由、健康检查、认证/转发协议、Minecraft zlib 压缩和必要的 Forge/Bungee 兼容;运行时后端可由代理插件或受限的 Bukkit 后端适配器注册。
|
||||
StrataProxy 是一个 Java 25 的 Minecraft 后端代理。它只做代理该做的事:接受玩家连接、选择可用后端、维持后端健康状态,并处理认证、转发、压缩及必要的 Forge/Bungee 协议兼容。
|
||||
|
||||
没有 Admin HTTP API、管理 CLI、数据包分析/抓取或 Prometheus/Grafana 资源。Bukkit 适配器仅拥有后端注册、心跳与下线权限,不是动态运维控制面。
|
||||
项目没有管理后台、HTTP Admin API、管理 CLI、查询协议、数据包分析或监控面板。运行期扩缩容通过代理插件 API 或受限的 Bukkit 后端适配器完成;两者都只能操作后端注册表,不能管理代理进程或读取玩家数据。
|
||||
|
||||
## 工程与产物
|
||||
|
||||
工程只有两个 Gradle 模块:
|
||||
|
||||
- `proxy-core`:可运行的代理、配置、网络转发与插件加载器。
|
||||
- `proxy-plugin-api`:第三方代理插件唯一需要依赖的公开 API。
|
||||
|
||||
`integrations/bukkit-backend-agent` 是独立的 Java 8 Bukkit 插件;它以 Spigot 1.8 API 编译,只使用 Bukkit 1.7.10 已有的基础 API,因此可用于 1.7.10 Bukkit 派生服务端。
|
||||
|
||||
## 构建与启动
|
||||
|
||||
需要 JDK 25。执行:
|
||||
|
||||
```powershell
|
||||
.\gradlew.bat --no-daemon check :proxy-core:installDist
|
||||
.\proxy-core\build\install\strataproxy\bin\strataproxy.bat --validate-config .\proxy-core\build\install\strataproxy\config\strataproxy.yml
|
||||
```
|
||||
|
||||
工程只保留两个模块:`proxy-core` 是完整的代理运行时(启动、配置、插件加载与网络转发),`proxy-plugin-api` 是唯一稳定的第三方插件契约。
|
||||
运行目录位于 `proxy-core\build\install\strataproxy\`。先复制默认配置并校验:
|
||||
|
||||
中文文档从 [docs/README.md](docs/README.md) 开始。
|
||||
```powershell
|
||||
Copy-Item proxy-core\src\main\resources\config\strataproxy.yml .\strataproxy.yml
|
||||
.\proxy-core\build\install\strataproxy\bin\strataproxy.bat --config .\strataproxy.yml --validate-config
|
||||
.\proxy-core\build\install\strataproxy\bin\strataproxy.bat --config .\strataproxy.yml
|
||||
```
|
||||
|
||||
`network.bind` 是玩家入口,`servers` 至少需要一个静态后端;若启用了 `backendAgent`,可以只通过动态注册提供后端。每次修改 YAML 后重启代理。
|
||||
|
||||
## 最小配置
|
||||
|
||||
下面是一个本机大厅的最小可用配置。其余字段可保留默认值:
|
||||
|
||||
```yaml
|
||||
network:
|
||||
bind: "0.0.0.0:25577"
|
||||
|
||||
registry:
|
||||
staticServers: true
|
||||
healthCheckEnabled: true
|
||||
healthCheckMode: "minecraft-status"
|
||||
|
||||
servers:
|
||||
- name: "lobby-1"
|
||||
address: "127.0.0.1:25565"
|
||||
tags: ["lobby"]
|
||||
weight: 100
|
||||
softCapacity: 500
|
||||
hardCapacity: 600
|
||||
drainMode: false
|
||||
```
|
||||
|
||||
常用配置边界:
|
||||
|
||||
- `healthCheckMode: tcp` 只检查 TCP 可连接;`minecraft-status` 还要求后端能正常回复服务器列表状态。
|
||||
- `forwarding.mode` 可选 `none`、`velocity-modern`、`bungee-legacy`、`bungee-guard`。使用 `velocity-modern` 或 `bungee-guard` 时必须同时设置 `forwarding.secret`,并在后端配置相同密钥。
|
||||
- `registry.persistenceEnabled: true` 会将标记为持久化的动态后端写入 `registry.persistencePath`;临时后端不会跨重启保留。
|
||||
- `network.proxyProtocol` 只能用于可信的 HAProxy 或负载均衡器之后,并且上游确实发送 PROXY protocol v1。
|
||||
|
||||
## 动态后端:Bukkit 服务端
|
||||
|
||||
官方 Bukkit 适配器用于让一个 Bukkit 服务端在启动时注册、定期发送心跳,并在停止时注销。代理端先启用一个仅监听本机的受限端点:
|
||||
|
||||
```yaml
|
||||
backendAgent:
|
||||
enabled: true
|
||||
bind: "127.0.0.1:25578"
|
||||
sharedSecret: "替换为至少 32 个字符的随机密钥"
|
||||
heartbeatTimeout: "30s"
|
||||
```
|
||||
|
||||
构建适配器:
|
||||
|
||||
```powershell
|
||||
.\gradlew.bat -p integrations\bukkit-backend-agent clean jar
|
||||
```
|
||||
|
||||
将 `integrations\bukkit-backend-agent\build\libs\strataproxy-bukkit-backend-agent-*.jar` 放入 Bukkit 的 `plugins/` 目录。首次启动后编辑 `plugins/StrataProxyBackendAgent/config.yml`:
|
||||
|
||||
```yaml
|
||||
proxy:
|
||||
host: "127.0.0.1"
|
||||
port: 25578
|
||||
sharedSecret: "与代理 backendAgent.sharedSecret 完全相同的至少 32 字符随机密钥"
|
||||
|
||||
backend:
|
||||
name: "survival-1"
|
||||
address: "127.0.0.1:25565"
|
||||
tags: ["survival"]
|
||||
weight: 100
|
||||
persistent: false
|
||||
|
||||
heartbeatSeconds: 10
|
||||
unregisterOnDisable: true
|
||||
```
|
||||
|
||||
`sharedSecret` 两端必须相同,且不能保留示例中的占位符;配置错误时插件会拒绝启动。端点只接受注册、心跳和注销,心跳超时后代理会移除该后端。建议保持 `bind` 在环回地址,或以防火墙限制到可信 Bukkit 主机。
|
||||
|
||||
## 代理插件
|
||||
|
||||
代理会从配置文件同级的 `plugins/` 目录加载插件 JAR。插件仅依赖 `dev.strataproxy:proxy-plugin-api`,不要依赖 `proxy-core` 的实现类。
|
||||
|
||||
本仓库开发时可先发布 API 到本机 Maven:
|
||||
|
||||
```powershell
|
||||
.\gradlew.bat :proxy-plugin-api:publishToMavenLocal
|
||||
```
|
||||
|
||||
插件项目依赖:
|
||||
|
||||
```kotlin
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("dev.strataproxy:proxy-plugin-api:0.1.0-SNAPSHOT")
|
||||
}
|
||||
```
|
||||
|
||||
JAR 根目录需要 `strataproxy-plugin.properties`:
|
||||
|
||||
```properties
|
||||
id=example
|
||||
name=Example Plugin
|
||||
version=1.0.0
|
||||
main=com.example.ExamplePlugin
|
||||
```
|
||||
|
||||
入口实现 `ProxyPlugin`。`PluginContext` 提供命令、事件、玩家查询/转服、后端查询/注册、调度器和插件日志。动态后端默认是临时的;选择 `ServerPersistence.PERSISTENT` 才会写入持久化注册表。插件只能修改自己创建的后端,不能覆盖 YAML 静态后端或其他插件的后端。
|
||||
|
||||
```java
|
||||
public final class ExamplePlugin implements ProxyPlugin {
|
||||
@Override
|
||||
public void onLoad(PluginContext context) {
|
||||
context.events().subscribe(ProxyStartedEvent.class,
|
||||
event -> context.logger().info("Example plugin ready"));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
不要在事件回调或命令处理中阻塞 Netty 线程;耗时操作请交给 `context.scheduler()`。代理内置玩家命令为 `/server <server>`、`/hub`、`/lobby`、`/servers` 和 `/glist`。
|
||||
|
||||
## 发布
|
||||
|
||||
`release` 会生成代理发行包、插件 API JAR、SBOM、校验和及元数据:
|
||||
|
||||
```powershell
|
||||
.\gradlew.bat --no-daemon release
|
||||
```
|
||||
|
||||
`publish` 会向已配置的 Gitea Maven 仓库发布 `proxy-plugin-api` 和 Bukkit 后端适配器。CI 使用同一套 Gradle 任务;不要把密钥写入配置样例或提交到仓库。
|
||||
+3
-13
@@ -127,16 +127,6 @@ gradle.projectsEvaluated {
|
||||
)
|
||||
into(releaseStaging)
|
||||
from("README.md")
|
||||
from("docs") {
|
||||
into("docs")
|
||||
exclude("history/**")
|
||||
}
|
||||
from("deployment") {
|
||||
into("deployment")
|
||||
}
|
||||
from("examples") {
|
||||
into("examples")
|
||||
}
|
||||
from("proxy-core/src/main/resources/config") {
|
||||
into("config")
|
||||
}
|
||||
@@ -178,7 +168,7 @@ gradle.projectsEvaluated {
|
||||
metadataFile.set(releaseMetadata)
|
||||
sbomFile.set(releaseSbom)
|
||||
checksumFile.set(releaseChecksum)
|
||||
chineseReadme.set(layout.projectDirectory.file("docs/README.md"))
|
||||
chineseReadme.set(layout.projectDirectory.file("README.md"))
|
||||
runtimeArtifacts.from(app.configurations.getByName("runtimeClasspath"))
|
||||
}
|
||||
|
||||
@@ -480,8 +470,8 @@ abstract class ReleaseAuditTask : DefaultTask() {
|
||||
val sbom = sbomFile.get().asFile.readText()
|
||||
val checksums = checksumFile.get().asFile.readText()
|
||||
val chineseDocs = chineseReadme.get().asFile.readText()
|
||||
listOf("StrataProxy 文档", "快速开始", "运维说明", "架构").forEach { token ->
|
||||
require(chineseDocs.contains(token)) { "Chinese documentation index missing $token" }
|
||||
listOf("StrataProxy", "构建与启动", "动态后端:Bukkit 服务端", "代理插件").forEach { token ->
|
||||
require(chineseDocs.contains(token)) { "Chinese documentation missing $token" }
|
||||
}
|
||||
listOf(
|
||||
"\"name\": \"strataproxy-",
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
# 部署
|
||||
|
||||
将 `proxy-core` 的 `installDist` 产物和 YAML 配置部署到目标主机即可。示例 systemd 与容器文件只暴露 Minecraft 监听端口 `25577`,注册表持久化路径通过 `STRATAPROXY_DATA_DIR` 控制。
|
||||
|
||||
```bash
|
||||
./gradlew --no-daemon :proxy-core:installDist
|
||||
```
|
||||
|
||||
启动前执行 `strataproxy --validate-config /path/to/strataproxy.yml`。生产环境不包含管理端口、指标端点或数据包抓取功能。
|
||||
@@ -1,21 +0,0 @@
|
||||
ARG JAVA_IMAGE=eclipse-temurin:25-jdk
|
||||
ARG RUNTIME_IMAGE=eclipse-temurin:25-jre
|
||||
|
||||
FROM ${JAVA_IMAGE} AS build
|
||||
WORKDIR /workspace
|
||||
COPY . .
|
||||
RUN ./gradlew --no-daemon :proxy-core:installDist
|
||||
|
||||
FROM ${RUNTIME_IMAGE}
|
||||
RUN useradd --system --home-dir /opt/strataproxy --shell /usr/sbin/nologin strataproxy
|
||||
WORKDIR /opt/strataproxy
|
||||
COPY --from=build /workspace/proxy-core/build/install/strataproxy/ /opt/strataproxy/
|
||||
RUN mkdir -p /opt/strataproxy/data \
|
||||
&& cp /opt/strataproxy/config/strataproxy-production.yml /opt/strataproxy/config/strataproxy.yml \
|
||||
&& chown -R strataproxy:strataproxy /opt/strataproxy
|
||||
USER strataproxy
|
||||
EXPOSE 25577
|
||||
VOLUME ["/opt/strataproxy/data"]
|
||||
ENV JAVA_OPTS="-Xms2g -Xmx2g -XX:MaxDirectMemorySize=2g -XX:+UseZGC -XX:+AlwaysPreTouch -XX:+ExitOnOutOfMemoryError -Dio.netty.leakDetection.level=disabled"
|
||||
ENTRYPOINT ["/opt/strataproxy/bin/strataproxy"]
|
||||
CMD ["/opt/strataproxy/config/strataproxy.yml"]
|
||||
@@ -1,46 +0,0 @@
|
||||
# 本地 Minecraft 1.7.10 后端池
|
||||
|
||||
此目录提供用于测试 StrataProxy 的本地三后端 Minecraft 1.7.10 环境脚本和配置。
|
||||
|
||||
## 后端
|
||||
|
||||
| 名称 | 地址 | 路由主机 | 标签 |
|
||||
| --- | --- | --- | --- |
|
||||
| lobby-1 | 127.0.0.1:25565 | lobby.local | lobby, mc-1.7.10 |
|
||||
| survival-1 | 127.0.0.1:25566 | survival.local | survival, mc-1.7.10 |
|
||||
| minigame-1 | 127.0.0.1:25567 | minigame.local | minigame, mc-1.7.10 |
|
||||
|
||||
脚本会按需从 Mojang 版本元数据下载服务端 jar 到 `bin/minecraft_server.1.7.10.jar`,并校验 SHA-1:
|
||||
|
||||
```text
|
||||
952438ac4e01b4d115c5fc38f891710c4941df29
|
||||
```
|
||||
|
||||
## 启动
|
||||
|
||||
先阅读并接受 Minecraft EULA;确认接受后运行:
|
||||
|
||||
```powershell
|
||||
.\deployment\local-minecraft-1.7.10\start-backends.ps1 -AcceptEula
|
||||
```
|
||||
|
||||
使用本地 1.7.10 配置启动 StrataProxy:
|
||||
|
||||
```powershell
|
||||
.\deployment\local-minecraft-1.7.10\start-proxy.ps1
|
||||
```
|
||||
|
||||
Minecraft 1.7.10 客户端连接:
|
||||
|
||||
```text
|
||||
127.0.0.1:25577
|
||||
```
|
||||
|
||||
## 检查与停止
|
||||
|
||||
```powershell
|
||||
.\deployment\local-minecraft-1.7.10\status.ps1
|
||||
.\deployment\local-minecraft-1.7.10\stop-backends.ps1
|
||||
```
|
||||
|
||||
各后端的标准输出和错误日志写在自己的后端目录中。Git 有意忽略生成的运行时文件:`bin/`、`backend-*/`、`*.pid` 和 `*.log`。
|
||||
@@ -1,121 +0,0 @@
|
||||
param(
|
||||
[switch] $AcceptEula,
|
||||
[string] $JavaExe = "java",
|
||||
[string] $Xms = "256M",
|
||||
[string] $Xmx = "768M"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$Root = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$Bin = Join-Path $Root "bin"
|
||||
$Jar = Join-Path $Root "bin\minecraft_server.1.7.10.jar"
|
||||
$ExpectedServerSha1 = "952438ac4e01b4d115c5fc38f891710c4941df29"
|
||||
|
||||
function Get-ServerJar {
|
||||
if (Test-Path -LiteralPath $Jar) {
|
||||
$ActualSha1 = (Get-FileHash -LiteralPath $Jar -Algorithm SHA1).Hash.ToLowerInvariant()
|
||||
if ($ActualSha1 -ne $ExpectedServerSha1) {
|
||||
throw "Server jar SHA-1 mismatch: expected $ExpectedServerSha1, got $ActualSha1"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Path $Bin -Force | Out-Null
|
||||
$Manifest = Invoke-RestMethod -Uri "https://piston-meta.mojang.com/mc/game/version_manifest_v2.json"
|
||||
$Version = $Manifest.versions | Where-Object { $_.id -eq "1.7.10" } | Select-Object -First 1
|
||||
if (-not $Version) {
|
||||
throw "Could not find Minecraft 1.7.10 in Mojang version manifest"
|
||||
}
|
||||
$VersionMetadata = Invoke-RestMethod -Uri $Version.url
|
||||
$ServerUrl = $VersionMetadata.downloads.server.url
|
||||
if (-not $ServerUrl) {
|
||||
throw "Minecraft 1.7.10 manifest does not include a server download"
|
||||
}
|
||||
|
||||
$TempJar = "$Jar.download"
|
||||
Invoke-WebRequest -Uri $ServerUrl -OutFile $TempJar
|
||||
$ActualSha1 = (Get-FileHash -LiteralPath $TempJar -Algorithm SHA1).Hash.ToLowerInvariant()
|
||||
if ($ActualSha1 -ne $ExpectedServerSha1) {
|
||||
Remove-Item -LiteralPath $TempJar -Force
|
||||
throw "Downloaded server jar SHA-1 mismatch: expected $ExpectedServerSha1, got $ActualSha1"
|
||||
}
|
||||
Move-Item -LiteralPath $TempJar -Destination $Jar -Force
|
||||
Write-Host "Downloaded Minecraft 1.7.10 server jar to $Jar"
|
||||
}
|
||||
|
||||
function Ensure-BackendConfig {
|
||||
param(
|
||||
[string] $Dir,
|
||||
[string] $Name,
|
||||
[int] $Port
|
||||
)
|
||||
|
||||
New-Item -ItemType Directory -Path $Dir -Force | Out-Null
|
||||
$ServerProperties = Join-Path $Dir "server.properties"
|
||||
if (Test-Path -LiteralPath $ServerProperties) {
|
||||
return
|
||||
}
|
||||
|
||||
$Properties = @(
|
||||
"server-ip=127.0.0.1",
|
||||
"server-port=$Port",
|
||||
"online-mode=false",
|
||||
"enable-query=false",
|
||||
"enable-rcon=false",
|
||||
"motd=StrataProxy $Name",
|
||||
"max-players=100",
|
||||
"spawn-protection=0",
|
||||
"view-distance=6",
|
||||
"difficulty=1",
|
||||
"gamemode=0",
|
||||
"white-list=false",
|
||||
"generate-structures=false"
|
||||
)
|
||||
Set-Content -LiteralPath $ServerProperties -Value $Properties -Encoding ASCII
|
||||
}
|
||||
|
||||
$Backends = @(
|
||||
@{ Name = "backend-lobby-1"; Port = 25565 },
|
||||
@{ Name = "backend-survival-1"; Port = 25566 },
|
||||
@{ Name = "backend-minigame-1"; Port = 25567 }
|
||||
)
|
||||
|
||||
Get-ServerJar
|
||||
|
||||
foreach ($Backend in $Backends) {
|
||||
$Dir = Join-Path $Root $Backend.Name
|
||||
Ensure-BackendConfig -Dir $Dir -Name $Backend.Name -Port $Backend.Port
|
||||
$Eula = Join-Path $Dir "eula.txt"
|
||||
$PidFile = Join-Path $Dir "server.pid"
|
||||
$OutLog = Join-Path $Dir "stdout.log"
|
||||
$ErrLog = Join-Path $Dir "stderr.log"
|
||||
|
||||
if (-not (Test-Path -LiteralPath $Eula)) {
|
||||
Set-Content -LiteralPath $Eula -Value "eula=false" -Encoding ASCII
|
||||
}
|
||||
if ($AcceptEula) {
|
||||
Set-Content -LiteralPath $Eula -Value "eula=true" -Encoding ASCII
|
||||
}
|
||||
if (-not (Select-String -LiteralPath $Eula -Pattern "^eula=true$" -Quiet)) {
|
||||
throw "EULA is not accepted for $($Backend.Name). Read Minecraft EULA, then rerun with -AcceptEula if you accept it."
|
||||
}
|
||||
|
||||
if (Test-Path -LiteralPath $PidFile) {
|
||||
$ExistingPid = (Get-Content -LiteralPath $PidFile -Raw).Trim()
|
||||
if ($ExistingPid -and (Get-Process -Id ([int] $ExistingPid) -ErrorAction SilentlyContinue)) {
|
||||
Write-Host "$($Backend.Name) already running on port $($Backend.Port), pid $ExistingPid"
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
$Args = @("-Xms$Xms", "-Xmx$Xmx", "-jar", $Jar, "nogui")
|
||||
$Process = Start-Process -FilePath $JavaExe `
|
||||
-ArgumentList $Args `
|
||||
-WorkingDirectory $Dir `
|
||||
-RedirectStandardOutput $OutLog `
|
||||
-RedirectStandardError $ErrLog `
|
||||
-WindowStyle Hidden `
|
||||
-PassThru
|
||||
Set-Content -LiteralPath $PidFile -Value $Process.Id -Encoding ASCII
|
||||
Write-Host "Started $($Backend.Name) on 127.0.0.1:$($Backend.Port), pid $($Process.Id)"
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
param(
|
||||
[string] $JavaHome = "C:\Program Files\Zulu\zulu-25"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$Root = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$Repo = Split-Path -Parent (Split-Path -Parent $Root)
|
||||
$Config = Join-Path $Root "strataproxy-1.7.10-local.yml"
|
||||
$Proxy = Join-Path $Repo "proxy-core\build\install\strataproxy\bin\strataproxy.bat"
|
||||
|
||||
if (-not (Test-Path -LiteralPath $Proxy)) {
|
||||
Push-Location $Repo
|
||||
try {
|
||||
$env:JAVA_HOME = $JavaHome
|
||||
& .\gradlew.bat --no-daemon :proxy-core:installDist
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
}
|
||||
|
||||
& $Proxy $Config
|
||||
@@ -1,36 +0,0 @@
|
||||
$ErrorActionPreference = "Stop"
|
||||
$Backends = @(
|
||||
@{ Name = "lobby-1"; Port = 25565 },
|
||||
@{ Name = "survival-1"; Port = 25566 },
|
||||
@{ Name = "minigame-1"; Port = 25567 }
|
||||
)
|
||||
|
||||
function Test-Port {
|
||||
param(
|
||||
[string] $HostName,
|
||||
[int] $Port,
|
||||
[int] $TimeoutMillis = 500
|
||||
)
|
||||
|
||||
$Client = [System.Net.Sockets.TcpClient]::new()
|
||||
try {
|
||||
$Connect = $Client.BeginConnect($HostName, $Port, $null, $null)
|
||||
if (-not $Connect.AsyncWaitHandle.WaitOne($TimeoutMillis)) {
|
||||
return $false
|
||||
}
|
||||
$Client.EndConnect($Connect)
|
||||
return $true
|
||||
} catch {
|
||||
return $false
|
||||
} finally {
|
||||
$Client.Close()
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($Backend in $Backends) {
|
||||
$State = if (Test-Port -HostName "127.0.0.1" -Port $Backend.Port) { "open" } else { "closed" }
|
||||
Write-Host "$($Backend.Name) 127.0.0.1:$($Backend.Port) $State"
|
||||
}
|
||||
|
||||
$ProxyState = if (Test-Port -HostName "127.0.0.1" -Port 25577) { "open" } else { "closed" }
|
||||
Write-Host "strataproxy 127.0.0.1:25577 $ProxyState"
|
||||
@@ -1,25 +0,0 @@
|
||||
$ErrorActionPreference = "Stop"
|
||||
$Root = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$Backends = @("backend-lobby-1", "backend-survival-1", "backend-minigame-1")
|
||||
|
||||
foreach ($Backend in $Backends) {
|
||||
$PidFile = Join-Path (Join-Path $Root $Backend) "server.pid"
|
||||
if (-not (Test-Path -LiteralPath $PidFile)) {
|
||||
Write-Host "$Backend is not tracked"
|
||||
continue
|
||||
}
|
||||
$PidText = (Get-Content -LiteralPath $PidFile -Raw).Trim()
|
||||
if (-not $PidText) {
|
||||
Remove-Item -LiteralPath $PidFile -Force
|
||||
Write-Host "$Backend has an empty pid file"
|
||||
continue
|
||||
}
|
||||
$Process = Get-Process -Id ([int] $PidText) -ErrorAction SilentlyContinue
|
||||
if ($Process) {
|
||||
Stop-Process -Id $Process.Id -Force
|
||||
Write-Host "Stopped $Backend, pid $PidText"
|
||||
} else {
|
||||
Write-Host "$Backend pid $PidText is not running"
|
||||
}
|
||||
Remove-Item -LiteralPath $PidFile -Force
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
network:
|
||||
bind: "0.0.0.0:25577"
|
||||
workerThreads: 0
|
||||
nativeTransport: true
|
||||
maxFrameBytes: "8mb"
|
||||
connectTimeoutMillis: 5000
|
||||
writeBufferLow: "4mb"
|
||||
writeBufferHigh: "16mb"
|
||||
maxConnections: 10000
|
||||
maxConnectionsPerAddress: 200
|
||||
maxNewConnectionsPerSecond: 0
|
||||
maxNewConnectionsPerAddressPerSecond: 0
|
||||
initialHandshakeTimeoutMillis: 5000
|
||||
proxyProtocol: false
|
||||
|
||||
registry:
|
||||
staticServers: true
|
||||
persistenceEnabled: false
|
||||
persistencePath: "data/registry.json"
|
||||
healthCheckEnabled: true
|
||||
healthCheckInterval: "5s"
|
||||
healthCheckTimeout: "2s"
|
||||
healthCheckMode: "minecraft-status"
|
||||
|
||||
compression:
|
||||
mode: off
|
||||
minThreshold: 256
|
||||
maxThreshold: 8192
|
||||
cpuGuard: 0.75
|
||||
rewriteEnabled: false
|
||||
rewriteMaxEventLoopDelayMillis: 25
|
||||
|
||||
observability:
|
||||
flushIntervalSeconds: 5
|
||||
|
||||
status:
|
||||
enabled: true
|
||||
motd: "StrataProxy local 1.7.10 pool"
|
||||
protocolName: "Minecraft 1.7.10"
|
||||
protocolVersion: 5
|
||||
maxPlayers: 300
|
||||
favicon: ""
|
||||
faviconPath: ""
|
||||
samplePlayers: []
|
||||
|
||||
auth:
|
||||
onlineMode: false
|
||||
rsaKeyBits: 1024
|
||||
verifyTokenBytes: 4
|
||||
sessionVerification: false
|
||||
sessionVerificationTimeout: "5s"
|
||||
|
||||
forwarding:
|
||||
mode: "none"
|
||||
secret: ""
|
||||
|
||||
native:
|
||||
enabled: true
|
||||
autoDetect: true
|
||||
preferNativeTransport: true
|
||||
requireNativeTransport: false
|
||||
preferOpenSslTls: false
|
||||
preferNativeCompression: false
|
||||
disabledFeatures: []
|
||||
forcedFeatures: []
|
||||
|
||||
servers:
|
||||
- name: "lobby-1"
|
||||
address: "127.0.0.1:25565"
|
||||
tags: ["lobby", "mc-1.7.10"]
|
||||
capabilities: []
|
||||
protocolRange: "5"
|
||||
weight: 100
|
||||
softCapacity: 80
|
||||
hardCapacity: 100
|
||||
drainMode: false
|
||||
metadata:
|
||||
group: "lobby"
|
||||
host: "lobby.local"
|
||||
route: "lobby"
|
||||
version: "1.7.10"
|
||||
- name: "survival-1"
|
||||
address: "127.0.0.1:25566"
|
||||
tags: ["survival", "mc-1.7.10"]
|
||||
capabilities: []
|
||||
protocolRange: "5"
|
||||
weight: 100
|
||||
softCapacity: 80
|
||||
hardCapacity: 100
|
||||
drainMode: false
|
||||
metadata:
|
||||
group: "survival"
|
||||
host: "survival.local"
|
||||
route: "survival"
|
||||
version: "1.7.10"
|
||||
- name: "minigame-1"
|
||||
address: "127.0.0.1:25567"
|
||||
tags: ["minigame", "mc-1.7.10"]
|
||||
capabilities: []
|
||||
protocolRange: "5"
|
||||
weight: 100
|
||||
softCapacity: 80
|
||||
hardCapacity: 100
|
||||
drainMode: false
|
||||
metadata:
|
||||
group: "minigame"
|
||||
host: "minigame.local"
|
||||
route: "minigame"
|
||||
version: "1.7.10"
|
||||
@@ -1,4 +0,0 @@
|
||||
# JVM options read by the Gradle application start script.
|
||||
JAVA_OPTS="-Xms2g -Xmx2g -XX:MaxDirectMemorySize=2g -XX:+UseZGC -XX:+AlwaysPreTouch -XX:+ExitOnOutOfMemoryError -Dio.netty.leakDetection.level=disabled"
|
||||
|
||||
STRATAPROXY_DATA_DIR="/var/lib/strataproxy"
|
||||
@@ -1,28 +0,0 @@
|
||||
[Unit]
|
||||
Description=StrataProxy Minecraft Proxy
|
||||
Documentation=file:/opt/strataproxy/deployment/README.md
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=strataproxy
|
||||
Group=strataproxy
|
||||
WorkingDirectory=/opt/strataproxy
|
||||
EnvironmentFile=/etc/strataproxy/strataproxy.env
|
||||
ExecStart=/opt/strataproxy/bin/strataproxy /opt/strataproxy/config/strataproxy-production.yml
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
TimeoutStopSec=30s
|
||||
LimitNOFILE=1048576
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
ReadWritePaths=/var/lib/strataproxy /var/log/strataproxy
|
||||
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||
SuccessExitStatus=130 143
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -1,13 +0,0 @@
|
||||
# StrataProxy 文档
|
||||
|
||||
| 目标 | 文档 |
|
||||
| --- | --- |
|
||||
| 本地启动 | [快速开始](quick-start.md) |
|
||||
| YAML 参数 | [配置说明](configuration.md) |
|
||||
| 部署与检查 | [运维说明](operations-manual.md) |
|
||||
| 插件与游戏内命令 | [插件开发](plugins.md) |
|
||||
| Bukkit 后端自动注册 | [Bukkit 适配器](../integrations/bukkit-backend-agent/README.md) |
|
||||
| 模块边界 | [架构](architecture.md) |
|
||||
| 协议支持范围 | [协议矩阵](protocol-version-matrix.md) |
|
||||
|
||||
文档只描述当前代码。Admin、数据包抓取、包异常分析和 Prometheus 端点均已删除。
|
||||
@@ -1,16 +0,0 @@
|
||||
# 架构与模块边界
|
||||
|
||||
```text
|
||||
第三方插件 ──> proxy-plugin-api
|
||||
│
|
||||
proxy-core
|
||||
```
|
||||
|
||||
| 工程 | 职责 |
|
||||
| --- | --- |
|
||||
| `proxy-core` | 完整代理运行时:启动、YAML 配置、插件加载、Minecraft 协议、Netty 转发、路由、注册表、健康检查与兼容处理 |
|
||||
| `proxy-plugin-api` | 唯一稳定的第三方插件契约 |
|
||||
|
||||
模块边界只按稳定契约划分,不按内部实现策略拆分。没有 `proxy-admin-cli` 或 HTTP 管理面;运行时后端只由已加载插件通过公开 API 管理。
|
||||
|
||||
`integrations/bukkit-backend-agent/` 是独立的 Java 8 Bukkit 适配器工程,不属于代理运行时模块。它只能通过受限的 `backendAgent` 端点注册、续租和下线自己的后端,不能作为管理 API 使用。
|
||||
@@ -1,50 +0,0 @@
|
||||
# 配置说明
|
||||
|
||||
配置文件是 YAML。未知字段会被忽略,因此升级后应删除已经不再支持的 `admin`、`packetAnalysis` 和旧的 `observability` 子字段。
|
||||
|
||||
```yaml
|
||||
network:
|
||||
bind: "0.0.0.0:25577"
|
||||
maxFrameBytes: "8mb"
|
||||
maxConnections: 10000
|
||||
|
||||
registry:
|
||||
staticServers: true
|
||||
persistenceEnabled: true
|
||||
persistencePath: "data/registry.json"
|
||||
healthCheckEnabled: true
|
||||
healthCheckMode: "tcp"
|
||||
|
||||
compression:
|
||||
mode: adaptive
|
||||
minThreshold: 256
|
||||
maxThreshold: 8192
|
||||
|
||||
observability:
|
||||
flushIntervalSeconds: 5
|
||||
|
||||
servers:
|
||||
- name: "lobby-1"
|
||||
address: "127.0.0.1:25565"
|
||||
tags: ["lobby"]
|
||||
protocolRange: "any"
|
||||
weight: 100
|
||||
```
|
||||
|
||||
`network` 控制监听、帧上限和连接限制;`registry` 控制静态后端、健康检查和本地持久化;`compression` 控制 Minecraft 压缩协商与重写;`observability.flushIntervalSeconds` 仅控制后端已观测负载写回间隔。
|
||||
|
||||
`status` 控制服务器列表响应,`auth` 控制 online-mode 登录校验,`forwarding` 可选 `none`、`velocity-modern`、`bungee-legacy` 或 `bungee-guard`,`native` 控制 Netty 原生传输偏好。完整默认值见 [strataproxy.yml](../proxy-core/src/main/resources/config/strataproxy.yml)。
|
||||
|
||||
## Bukkit 后端自动注册
|
||||
|
||||
`backendAgent` 默认关闭,且不是 Admin API。启用后只允许持有共享密钥的后端适配器注册、发送心跳或下线自己的服务:
|
||||
|
||||
```yaml
|
||||
backendAgent:
|
||||
enabled: true
|
||||
bind: "127.0.0.1:25578"
|
||||
sharedSecret: "至少32字符的随机密钥"
|
||||
heartbeatTimeout: "30s"
|
||||
```
|
||||
|
||||
若 Bukkit 服务在另一台受保护的主机,可把 `bind` 改为内网地址,并通过防火墙只允许该主机访问。适配器位于 [`integrations/bukkit-backend-agent`](../integrations/bukkit-backend-agent),其 `config.yml` 的密钥必须完全一致;心跳超时后代理会移除该适配器注册的后端。
|
||||
@@ -1,37 +0,0 @@
|
||||
# JavaDoc 参考
|
||||
|
||||
本文说明项目源码级 JavaDoc 的组织方式,以及如何在本地生成 API 参考文档。
|
||||
|
||||
## 生成
|
||||
|
||||
```powershell
|
||||
.\gradlew.bat javadoc
|
||||
```
|
||||
|
||||
生成的 HTML 会写入各模块的 `build/docs/javadoc` 目录,例如:
|
||||
|
||||
- `proxy-core/build/docs/javadoc`
|
||||
- `proxy-plugin-api/build/docs/javadoc`
|
||||
|
||||
大规模修改注释后,建议强制重跑,避免 Gradle up-to-date 状态隐藏文档问题:
|
||||
|
||||
```powershell
|
||||
.\gradlew.bat --rerun-tasks javadoc
|
||||
```
|
||||
|
||||
## 文档范围
|
||||
|
||||
本项目的 JavaDoc 重点覆盖公开契约:
|
||||
|
||||
- `proxy-core`:代理启动、YAML 配置、插件加载、后端服务器描述、路由、Minecraft codec、Netty 生命周期和运行时策略。这些包是代理内部实现,不单独作为 API 发布。
|
||||
- `proxy-plugin-api`:插件生命周期、命令、事件、调度器、玩家服务和服务器服务契约。
|
||||
|
||||
包私有 relay handler 和底层实现辅助类只在行为不直观、或影响公开契约时补充注释。
|
||||
|
||||
## 维护规则
|
||||
|
||||
- 公开接口、公开 record、公开 enum、公开 class 和公开构造器都应有 JavaDoc。
|
||||
- record 的 JavaDoc 应说明字段语义、单位和默认行为。
|
||||
- 返回 Netty `ByteBuf` 所有权的方法必须说明由谁释放。
|
||||
- 跨模块传播的诊断字符串、拒绝原因、阈值和超时单位应在边界处说明。
|
||||
- 正式用户文档统一维护在 `docs/` 根目录;历史验证资料仅保存在源码仓库中,不随发布包分发。
|
||||
@@ -1,14 +0,0 @@
|
||||
# 运维说明
|
||||
|
||||
生产运行只需要代理进程、一个 YAML 配置文件和已声明的后端。后端增删、权重或排空状态通过配置变更和重启完成。
|
||||
|
||||
```powershell
|
||||
.\strataproxy.bat --config .\strataproxy.yml --validate-config
|
||||
.\strataproxy.bat --config .\strataproxy.yml
|
||||
```
|
||||
|
||||
上线前确认监听端口可达、每个后端的 TCP 或 Minecraft status 健康检查正常,并根据需要启用 online-mode 和受保护的转发密钥。
|
||||
|
||||
本项目不提供 Admin HTTP API、Prometheus 指标端点、数据包抓取或运行时后端管理。
|
||||
|
||||
容器和 systemd 示例见 [deployment](../deployment/README.md)。
|
||||
-108
@@ -1,108 +0,0 @@
|
||||
# 插件和游戏内命令
|
||||
|
||||
StrataProxy 会从当前配置文件旁边的 `plugins/` 目录加载代理插件。插件 jar 是可选的;目录不存在时代理照常启动。
|
||||
|
||||
公开插件接口是 `dev.strataproxy:proxy-plugin-api` artifact。插件项目只应该依赖这个 API;`proxy-core` 是内部实现细节。
|
||||
|
||||
在本仓库本地开发时,先发布 API 到本机 Maven:
|
||||
|
||||
```powershell
|
||||
.\gradlew.bat :proxy-plugin-api:publishToMavenLocal
|
||||
```
|
||||
|
||||
插件项目使用:
|
||||
|
||||
```kotlin
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("dev.strataproxy:proxy-plugin-api:0.1.0-SNAPSHOT")
|
||||
}
|
||||
```
|
||||
|
||||
## 内置玩家命令
|
||||
|
||||
这些命令由代理拦截,不会继续转发到后端服务器:
|
||||
|
||||
```text
|
||||
/server <server>
|
||||
/hub
|
||||
/lobby
|
||||
/servers
|
||||
/glist
|
||||
```
|
||||
|
||||
`/server`、`/hub` 和 `/lobby` 使用与受支持 BungeeCord `Connect` plugin message 相同的类 Bungee 后端重登录转服流程。
|
||||
|
||||
## 插件入口
|
||||
|
||||
插件 jar 可以在 jar 根目录放置 `strataproxy-plugin.properties`:
|
||||
|
||||
```properties
|
||||
id=example
|
||||
name=Example Plugin
|
||||
version=1.0.0
|
||||
main=com.example.ExamplePlugin
|
||||
```
|
||||
|
||||
也可以使用标准 Java `ServiceLoader`,提供 `dev.strataproxy.plugin.ProxyPlugin` provider。
|
||||
|
||||
插件可以通过 `PluginContext` 注册命令、订阅事件、查询玩家和服务器、注册动态后端、调度异步任务、发起玩家转服。插件代码不要阻塞 Netty event loop。
|
||||
|
||||
## 动态后端注册
|
||||
|
||||
插件可通过 `context.servers().register(...)` 注册运行期后端,用于服务发现、房间服、副本服或外部编排系统同步。默认注册是 `ServerPersistence.EPHEMERAL`,只影响当前运行中的 proxy;需要重启后保留时,显式使用 `ServerPersistence.PERSISTENT`。
|
||||
|
||||
插件注册的 server 会自动写入 owner metadata。默认情况下,插件只能替换、删除或切换 drain 自己注册的 server,不能覆盖 YAML 静态 server 或其他插件注册的 server。
|
||||
|
||||
```java
|
||||
var registration = new ServerRegistration(
|
||||
"arena-1",
|
||||
new InetSocketAddress("127.0.0.1", 25570),
|
||||
Set.of("arena"),
|
||||
Set.of("modern-forwarding"),
|
||||
ServerProtocolRange.any(),
|
||||
100,
|
||||
80,
|
||||
100,
|
||||
false,
|
||||
Map.of("group", "arena"),
|
||||
ServerPersistence.EPHEMERAL);
|
||||
|
||||
context.servers().register(registration).thenAccept(result -> {
|
||||
if (!result.success()) {
|
||||
context.logger().warn("Failed to register backend: {} {}", result.outcome(), result.message());
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
能力名使用和配置文件一致的语义,大小写不敏感,`-` 会按 `_` 规范化,例如 `modern-forwarding` 会映射到 `MODERN_FORWARDING`。
|
||||
|
||||
## 最小插件
|
||||
|
||||
```java
|
||||
public final class HelloPlugin implements ProxyPlugin {
|
||||
@Override
|
||||
public void onLoad(PluginContext context) {
|
||||
context.commands().register(new CommandSpec(
|
||||
"hello",
|
||||
List.of(),
|
||||
"",
|
||||
"Send a hello message.",
|
||||
command -> CompletableFuture.completedFuture(
|
||||
CommandResult.ok("Hello, " + command.source().name() + "."))));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
仓库里提供了独立示例 `examples/hello-plugin`。本地发布 API 后可以构建:
|
||||
|
||||
```powershell
|
||||
.\gradlew.bat :proxy-plugin-api:publishToMavenLocal
|
||||
.\gradlew.bat -p examples/hello-plugin build
|
||||
```
|
||||
|
||||
把生成的插件 jar 放到当前 StrataProxy 配置文件旁边的 `plugins/` 目录,然后重启代理。
|
||||
@@ -1,70 +0,0 @@
|
||||
# 协议版本能力矩阵
|
||||
|
||||
这张表是 StrataProxy 的 Minecraft 协议兼容契约。以后新增版本时,必须同时更新 `MinecraftProtocolProfile`、测试和这份文档。
|
||||
|
||||
状态含义:
|
||||
|
||||
- `已支持`:已经进入 `MinecraftProtocolProfile`,并有针对性测试覆盖。
|
||||
- `部分支持`:有部分行为,但不能宣称完整多版本生产兼容。
|
||||
- `未支持`:不能对外宣称稳定兼容;必须先补 profile 和测试。
|
||||
|
||||
## 当前运行矩阵
|
||||
|
||||
| Minecraft Java 版本 | Protocol | 状态 | 登录压缩 | 上行命令包 | Custom Payload 格式 | 后端切服 | Legacy Forge/FML |
|
||||
| --- | ---: | --- | --- | --- | --- | --- | --- |
|
||||
| 1.7.10 | 5 | 已支持当前 1.7.10/legacy 切服目标 | 不启用 vanilla login compression | `0x01` chat message | 上行 unsigned-short 长度,下行 varshort 长度 | Respawn 切服;Forge 安全路径为 Join Game + Respawn | 部分支持:REGISTER 跟踪、reset 注入、握手观测/gate、非 FML payload 排队、plugin-channel replay |
|
||||
| 1.8.x | 47 | 已支持当前压缩和 legacy 切服目标 | 支持 Login Set Compression `0x03` | `0x01` chat message | 上下行都是 remaining bytes | 支持压缩/未压缩 Respawn 切服;Forge 安全路径为 Join Game + Respawn | 部分支持:压缩握手观测/gate、压缩 race suppression、压缩 REGISTER replay |
|
||||
| 1.20.1 | 763 | 部分支持 | 支持 | `0x03`、`0x04`、`0x05` | 只在已有 sampler 覆盖范围内支持现代上行 payload | 不支持 legacy backend replacement | 不支持 legacy Forge/FML 状态机 |
|
||||
| 其他 1.9+ 版本 | 各不相同 | 未支持 | 不能只按版本号推断 | 未定义 | 未定义 | 未支持 | 未支持 |
|
||||
| 当前/latest Java 版本 | 各不相同 | 未支持,直到补 profile | 必须从目标版本协议数据读取 | 必须建模 | 必须建模 | 必须建模 | 现代模组加载器需要单独状态机 |
|
||||
|
||||
重要压缩规则:protocol 5 不启用 vanilla 登录压缩。旧代理里存在 1.7.x play-state 压缩包的历史实现,但 StrataProxy 不能把它当作普通 login compression。
|
||||
|
||||
## 新版本必须补齐的 Profile 字段
|
||||
|
||||
| 字段 | 原因 |
|
||||
| --- | --- |
|
||||
| protocol number | 路由过滤和 status response 需要 |
|
||||
| login packet id | Login Success、Disconnect、Encryption Request、Set Compression 都依赖它 |
|
||||
| compression framing | 登录协商后 packet 是否压缩以及如何解码 |
|
||||
| serverbound command packet id | `/server` 等代理命令必须被代理吃掉,不能发给后端 |
|
||||
| custom payload packet id | Forge/Fabric/Bungee/Velocity plugin message 都依赖它 |
|
||||
| custom payload 长度格式 | 1.7.10 和 1.8 不同,现代版本又是另一套 payload 语义 |
|
||||
| Join Game / Respawn id 和布局 | 切服时要安全转换新后端首个 Join Game |
|
||||
| player list / scoreboard / team 清理包 | 安全切服需要清客户端状态 |
|
||||
| Forge/mod-loader 握手阶段 | 大型模组服切服需要 reset、registry 和 payload 排队 |
|
||||
| forwarding/login plugin 行为 | Velocity modern、Bungee legacy 身份转发都和版本有关 |
|
||||
|
||||
## 每个版本的测试门槛
|
||||
|
||||
| 门槛 | 1.7.10 | 1.8.x | 1.20.1 | 新版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 命令拦截 | 已覆盖 | 通过 legacy profile 路径覆盖 | 已覆盖 | 必须覆盖 |
|
||||
| 真实 TCP 后端切服 | 已覆盖 protocol 5 `/server` | 已有压缩切服单元覆盖 | 未覆盖 | 宣称切服支持前必须覆盖 |
|
||||
| 登录压缩 | 明确禁用 | 已覆盖 | 已覆盖现代路径 | 必须覆盖 |
|
||||
| custom payload 解析 | 已覆盖 | 已覆盖压缩/未压缩 | 部分覆盖 | 必须覆盖 |
|
||||
| Forge 握手跟踪 | 已覆盖 | 已覆盖压缩/未压缩 | 不适用 | 按 Forge/Fabric 设计补 |
|
||||
| Forge race suppression | 已覆盖 | 已覆盖压缩/未压缩 | 不适用 | legacy Forge 适用时必须覆盖 |
|
||||
| plugin channel REGISTER replay | 已覆盖 | 已覆盖压缩/未压缩 | 不适用 | 需要 replay 的版本必须覆盖 |
|
||||
| 真实大型模组服验收 | 尚未证明 | 尚未证明 | 不适用 | 生产宣称前必须验收 |
|
||||
|
||||
## 实现规则
|
||||
|
||||
新增版本时,不要直接在 relay handler 里散落 packet id。先扩展 `MinecraftProtocolProfile`,再让 relay/controller 通过 profile 能力工作。如果一个行为无法用 profile 表达,说明应该提取专门状态机,而不是继续在 relay 里加版本判断。
|
||||
|
||||
## 后续路线
|
||||
|
||||
1. 抽出明确的 `ConnectionStateMachine`:登录、压缩、play、mod-loader 阶段。
|
||||
2. 抽出 `TransferOrchestrator`:切服生命周期、初始 clientbound 包、回滚和指标。
|
||||
3. `MinecraftProtocolProfile` 只保留数据:packet id、格式、布局和能力开关。
|
||||
4. 按版本组补 profile 和测试,再宣称支持:
|
||||
- 1.9-1.12.2:legacy Forge 时代。
|
||||
- 1.13-1.16.5:扁平化与 namespaced payload 过渡。
|
||||
- 1.17-1.18.2:现代网络变更。
|
||||
- 1.19-1.20.6:签名聊天、登录/configuration 过渡。
|
||||
- 1.21+ 和 26.x 当前版本。
|
||||
|
||||
## 参考
|
||||
|
||||
- Minecraft Wiki 的 protocol version 数据说明,现代构建可从 client/server jar 的 `version.json` 读取 `protocol_version`。
|
||||
- Mojang 已宣布 Java Edition 从 2026 年开始使用 `26.x` 年份式版本号;因此版本名和 protocol number 必须分开建模。
|
||||
@@ -1,23 +0,0 @@
|
||||
# 快速开始
|
||||
|
||||
StrataProxy 是面向 Minecraft 的静态后端代理:监听客户端连接、按路由选择后端,并处理认证、转发协议、压缩和 Forge/Bungee 兼容所需的协议帧。
|
||||
|
||||
## 构建与校验
|
||||
|
||||
```powershell
|
||||
.\gradlew.bat --no-daemon check :proxy-core:installDist
|
||||
```
|
||||
|
||||
代理程序在 `proxy-core\build\install\strataproxy\`。
|
||||
|
||||
## 配置并启动
|
||||
|
||||
```powershell
|
||||
Copy-Item proxy-core\src\main\resources\config\strataproxy.yml .\strataproxy.yml
|
||||
.\proxy-core\build\install\strataproxy\bin\strataproxy.bat --config .\strataproxy.yml --validate-config
|
||||
.\proxy-core\build\install\strataproxy\bin\strataproxy.bat --config .\strataproxy.yml
|
||||
```
|
||||
|
||||
至少配置一个 `servers` 后端。修改 YAML 后重启代理生效;没有 HTTP 管理端口或管理令牌。动态后端仅由已加载插件通过 API 注册、下线或切换 drain 状态。
|
||||
|
||||
详见[配置说明](configuration.md)和[运维说明](operations-manual.md)。
|
||||
@@ -1,17 +0,0 @@
|
||||
plugins {
|
||||
`java-library`
|
||||
}
|
||||
|
||||
group = "example.strataproxy"
|
||||
version = "1.0.0"
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion.set(JavaLanguageVersion.of(25))
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("dev.strataproxy:proxy-plugin-api:0.1.0-SNAPSHOT")
|
||||
compileOnly("org.slf4j:slf4j-api:2.0.18")
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
dependencyResolutionManagement {
|
||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = "strataproxy-hello-plugin"
|
||||
@@ -1,37 +0,0 @@
|
||||
package example.strataproxy.hello;
|
||||
|
||||
import dev.strataproxy.plugin.PluginContext;
|
||||
import dev.strataproxy.plugin.ProxyPlugin;
|
||||
import dev.strataproxy.plugin.command.CommandResult;
|
||||
import dev.strataproxy.plugin.command.CommandSpec;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public final class HelloPlugin implements ProxyPlugin {
|
||||
/**
|
||||
* Creates HelloPlugin.
|
||||
*/
|
||||
public HelloPlugin() {
|
||||
}
|
||||
|
||||
private PluginContext context;
|
||||
|
||||
@Override
|
||||
/** Provides on load. */
|
||||
public void onLoad(PluginContext context) {
|
||||
this.context = context;
|
||||
context.commands().register(new CommandSpec(
|
||||
"hello",
|
||||
List.of(),
|
||||
"",
|
||||
"Send a hello message.",
|
||||
command -> CompletableFuture.completedFuture(CommandResult.ok("Hello, " + command.source().name() + "."))));
|
||||
}
|
||||
|
||||
@Override
|
||||
/** Provides on enable. */
|
||||
public void onEnable() {
|
||||
context.logger().info("Hello plugin enabled");
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
id=hello
|
||||
name=Hello Plugin
|
||||
version=1.0.0
|
||||
main=example.strataproxy.hello.HelloPlugin
|
||||
@@ -1,9 +0,0 @@
|
||||
# StrataProxy Bukkit 后端适配器
|
||||
|
||||
这是独立的 Java 8 Bukkit 插件,不属于 StrataProxy 的 Gradle 多模块工程。它以 Bukkit/Spigot 1.8 API 编译,但只调用 Bukkit 1.7.10 已有的基础 API,因此可运行在 1.7.10 Bukkit 派生端。它在启动时向代理的 `backendAgent` 端点注册本服务器,随后发送心跳;关闭时可主动下线。
|
||||
|
||||
先在代理配置启用 `backendAgent`,并设置至少 32 字符的随机 `sharedSecret`。然后将同一密钥写入本插件 `config.yml`,按实际服务器修改 `backend.name`、`backend.address`、标签、容量和持久化选项。
|
||||
|
||||
构建:`gradle jar`。将生成的 `build/libs/strataproxy-bukkit-backend-agent-*.jar` 放入 Bukkit 的 `plugins/` 目录后重启。
|
||||
|
||||
该端点只接受注册、心跳和下线,不能读取玩家、执行命令或修改其他代理设置。
|
||||
Reference in new issue
Block a user