307 Commits
Author SHA1 Message Date
layue13 eca0102c06 Merge pull request #18 from layue13/fix/listener-close-quiet-period
Build and publish / build (push) Successful in 5m6s
Build and publish / publish (push) Successful in 45s
fix: 关闭监听器时同时关闭 boss 与 worker 事件循环
2026-10-24 01:13:08 +08:00
layue13andClaude Opus 5.5 39e7f11a96 fix: 关闭监听器时同时关闭 boss 与 worker 事件循环
ProxySessionListener.close() 原先等 boss 组 shutdownGracefully 完成后才开始关闭
worker 组。两组各自要等 2 秒静默期,所以每次 close 至少约 4 秒。测试用
close().get(5, SECONDS) 收尾,在较慢的 Gitea runner 上 SessionTransferTest 有两个
用例因此超时(run 14129);本机 SessionTransferTest 每个用例也都在 4.16 秒以上,最慢
5.18 秒。

改为同时开始关闭两组,两者都结束后再完成 shutdown。各组仍保留默认静默期,关闭前已
提交的任务照常执行。本机 SessionTransferTest 单用例中位数 4.19 秒降到 2.15 秒,最慢
5.18 秒降到 3.13 秒。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 01:05:53 +08:00
layue13 2ae0af8bae Merge pull request #15 from layue13/perf/client-websocket-codec
perf(client-mod): one WebSocket message per batch, TCP_NODELAY on ws/wss
2026-10-23 17:50:15 +08:00
layue13 cd57bef0fd Merge pull request #14 from layue13/perf/websocket-cdn
perf: WebSocket 经 CDN:wss 改用 BoringSSL、保活 Ping、整合包形态基准
2026-10-23 17:50:11 +08:00
layue13 590e594e59 Merge pull request #17 from layue13/fix/shutdown-accept-flake
test: 修复 shutdownWhileAccepting… 在 Linux 上的偶发超时
2026-10-23 17:50:07 +08:00
layue13andClaude Opus 5.5 6d196a83bb test: 修复关闭监听时半开连接导致的偶发超时
shutdownWhileAcceptingClientsClosesEveryRegisteredSession 在 Linux CI 上偶发
SocketTimeoutException。在 Docker(Linux, 4 CPU)中复现 3/80,超时时 ss -tan 显示
卡住的客户端为 ESTAB,而服务端端口上没有该四元组的任何 socket:内核在监听 socket
关闭的竞争窗口内丢弃了握手的最后一个 ACK 且不发 RST,Netty 从未 accept 这条连接,
客户端不发数据就永远收不到任何东西。

读超时时改为写一个字节并要求收到 RST:无服务端 socket 必然回 RST;若代理 accept
后泄漏了连接,字节会被接收、读仍然超时,测试依旧失败。修复后 Docker 中 150/150 通过,
其中 8 次走到半开分支。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 17:36:30 +08:00
layue13 8cd0dcaaa0 Merge pull request #16 from layue13/fix/plugin-disable-deadlock
fix: 关闭插件宿主时不再持有宿主锁等待 onDisable
2026-10-23 17:12:21 +08:00
layue13andClaude Opus 5.5 85f56d042c fix: 关闭插件宿主时不再持有宿主锁等待 onDisable
- PluginHost.close() 原本整个方法持有宿主锁,包括等待各插件 onDisable 的最长 10 秒。插件在
  onDisable 里关闭自己的命令注册(文档推荐的做法)时,CommandService 的注销要拿同一把锁,
  于是一直等到截止时间被放弃:onDisable 后面的清理(线程池、数据库连接池)不会执行,日志里
  出现 “onDisable exceeded shutdown deadline”。AetherShard 每次停机都会遇到
- 现在只在 onDisable 之前和之后的步骤持锁,等待插件时不持锁;每个插件的 deactivateAndRemove
  仍在锁内。同时调用 close() 的第二个线程等第一个完成后返回,与之前被锁挡住时的效果一致
- PluginHostTest:插件在 onDisable 里关闭命令注册,close() 远早于截止时间返回且 onDisable
  执行完;修复前该测试失败

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 16:47:13 +08:00
layue13andClaude Opus 5.5 b72c609aec perf(client-mod): keep the batching encoder, drop the slice decoder
Verdict of the 2026-10-23 client codec record: ClientFrameEncoder sends
12x fewer messages at 51-56% less event-loop CPU per packet and is kept.
ClientFrameDecoder missed the rule (codec-only CPU -8-18% with
overlapping ranges; worse once vanilla's splitter runs behind it), so the
client keeps Netty's WebSocket13FrameDecoder. README protocol notes cover
TCP_NODELAY and one message per batch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 16:44:35 +08:00
layue13andClaude Opus 5.5 b7d6497ca8 perf: WebSocket 经 CDN:wss 改用 BoringSSL、保活 Ping、整合包形态基准
- ProxySessionBenchmark 新增 --profile modded(仿大型整合包的双向包组与 2 MiB 登录突发,逐字节校验)、
  --websocket-tls 1(keytool 一次性证书的 wss)和 --client-coalesce 1。
- wss 监听改用随包附带的 BoringSSL(netty-tcnative-boringssl-static 2.0.84):TLS 占 wss 代理 I/O CPU 的 55%,
  换用后每帧 CPU 在每一对配对测量中都更低(窗口 1 -22%,窗口 8 -36%),帧率 +31%/+34%;其他平台回落 JDK,
  启动日志标明所用实现。jar 由 10.4 MB 增至 16.5 MB。
- 新增 websocket.pingIntervalSeconds(默认 30,0 关闭):升级后代理静默不超过该时长,期间无写出就发空 Ping,
  避免 CDN/负载均衡在安静的登录、选服阶段按空闲超时断开。IdleStateHandler 版本在窗口 8 多耗 7.6% CPU,
  未达规则;改为写时置位标志、每半个间隔检查的实现,JFR 中几乎不可见。
- 文档:WebSocket 接入新增“经 CDN 部署”,更正消息大小描述;记录见
  testing/benchmarks/results/2026-10-23-websocket-cdn.md。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 16:40:48 +08:00
layue13andClaude Opus 5.5 1decc44081 perf(client-mod): candidate WebSocket codec, codecBenchmark and decision rule
TCP_NODELAY on ws/wss; ClientFrameEncoder (one message per batch) and
ClientFrameDecoder (retained slices) with tests. The decision rule is
recorded before the measured runs; the verdict follows in a later commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 16:29:46 +08:00
layue13 6224d3deb4 Merge pull request #13 from layue13/feat/admin-console
feat: 管理控制台(JLine)与内置命令
2026-10-23 15:50:18 +08:00
layue13andClaude Opus 5.5 284c2f81cf feat: 管理控制台(JLine)与内置命令
- core.admin.AdminView:在线玩家(地址、TCP/WebSocket、所在服务器、在线时长)、服务器
  (地址、人数、来源)与状态(版本、运行时长、传输层、监听地址、堆内存、最近 10 分钟活动)
  的只读快照;不从控制台线程直接读取会话状态
- Session 在发布玩家时记录连接详情;ProxySessionListener.onlinePlayers()
- ConnectionLog 用 RecentCounter(10 个一分钟桶)统计加入、离开、拒绝、转服与失败;
  连接数上限与插件池拒绝计入过载
- app.console:Console 在终端中使用 JLine(提示符固定在底部、历史、Tab 补全),否则按行读取
  标准输入;ConsoleLogAppender 让日志打印在提示符上方并为警告/错误着色
- 内置命令 help/list/servers/player/status/send/kick/loglevel/stop,先于插件控制台命令;
  同名插件命令在启动时警告;send/kick/loglevel/stop 写入 moonbridge.admin
- 依赖:JLine 3.30.17(reader、terminal、FFM 提供者),logback 改为编译期依赖
- 文档:operations.md 控制台命令、logging.md、CLAUDE.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 21:59:09 +08:00
layue13 1d712ac5c6 Merge pull request #12 from layue13/perf/websocket-coalescing
perf: WebSocket 出站每次 flush 合并为一条二进制消息
2026-10-22 21:24:08 +08:00
layue13andClaude Opus 5.5 21a5adf18d perf: WebSocket 出站每次 flush 合并为一条二进制消息
- WebSocketFrameAdapter:flush 前写入的字节用 CoalescingBufferQueue 合并为一条
  BinaryWebSocketFrame,最大 64 KiB。之前每个 Minecraft 帧一条消息,而 Netty 的编码器对
  小于 1 KiB 的消息每条都分配并复制一次。每次写入的 promise 在承载它的消息写出时完成;
  未 flush 的写入在关闭时失败并释放;排队字节计入通道可写性。入站不变
- ProxySessionBenchmark:新增 --websocket 1,代理阶段客户端走 ws://
- 记录 testing/benchmarks/results/2026-10-22-websocket-coalescing:burst32 每帧 CPU 低 21%
  且范围不重叠、吞吐更高;window 1 无变化;window 16 噪声大,补跑 3 对后合计无回退。
  满足事先规则,采用

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 20:56:00 +08:00
layue13 0253130760 Merge pull request #11 from layue13/feat/spigot-profile-adapter
perf: Spigot/CraftBukkit 1.7.10 上读取 GameProfile 也不再用反射
2026-10-22 20:23:49 +08:00
layue13andClaude Opus 5.5 547ba98f8f perf: Spigot/CraftBukkit 1.7.10 上读取 GameProfile 也不再用反射
- SpigotProfileAccess:直接调用 org.bukkit.craftbukkit.v1_7_R4.entity.CraftPlayer#getProfile
  与重定位到 net.minecraft.util.com.mojang.authlib 的 authlib。签名用 javap 从
  spigot-1.7.10-R0.1-SNAPSHOT(build 1649)和 craftbukkit-1.7.10-R0.1 读取,两者一致;
  五个调用的描述符逐一与 Spigot JAR 核对
- 选择顺序:Uranium → Spigot 1.7.10 → 缓存反射回退
- src/serverStubs 加入对应的编译期副本;verifyBackendJar 额外拒绝 net/minecraft/
- 测试:SpigotProfileAccessTest;文档更新

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 20:04:08 +08:00
layue13 36dd9ebb33 Merge pull request #8 from layue13/feat/plugin-dependencies
feat: 插件之间的依赖、类共享与类型化服务
2026-10-22 19:42:23 +08:00
layue13 74afaba6f8 Merge remote-tracking branch 'origin/main' into feat/plugin-dependencies
# Conflicts:
#	proxy/core/src/main/java/dev/moonbridge/core/plugin/PluginHost.java
2026-10-22 19:36:10 +08:00
layue13 d05dca7ada Merge pull request #10 from layue13/feat/zero-reflection
perf: Uranium 上读取 GameProfile 不再用反射,代理用 MethodHandle 创建插件
2026-10-22 19:33:44 +08:00
layue13 ee46cd8068 Merge pull request #9 from layue13/perf/relay-batch-completion
perf: 去掉冷路径上的重复开销,记录未采用的中继批量完成实验
2026-10-22 19:33:31 +08:00
layue13andClaude Opus 5.5 4565af2475 perf: Uranium 上读取 GameProfile 不再用反射,代理用 MethodHandle 创建插件
- 后端:ProfileAccess 按服务器选择访问方式,启动时选一次。Uranium 使用编译进 JAR 的
  UraniumProfileAccess(CraftPlayer#getProfile、authlib 1.5.16,签名来自 TDLM/Uranium 源码与
  authlib 字节码),没有反射;其他服务器(如 Spigot 1.7.10)使用缓存反射回退
  ReflectiveProfileAccess;编译调用链接失败时记警告并改用回退
- 剥离会话证明的算法只保留一份,两种访问方式共用
- src/serverStubs:只用于编译和测试的服务器类副本,不进 JAR;verifyBackendJar 额外检查
  不含 com/mojang/
- 代理:PluginConstructors 用 MethodHandles.publicLookup().findConstructor 创建插件,
  不再使用 java.lang.reflect 与 ServiceLoader
- 测试:UraniumProfileAccessTest、PluginConstructorsTest;文档说明各服务器的访问方式

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 19:19:41 +08:00
layue13andClaude Opus 5.5 25a7d0e1bb test: 转服截止测试把后端连接被重置也视为代理已关闭
cutoverTimesOutWhenOldBackendWriteNeverCompletes 在 CI 上偶发失败:代理在截止后关闭候选
后端连接时,若该连接上还有未读取的后端帧,Linux 会发送 RST,后端读到 Connection reset
而不是 EOF。两者都表示代理已关闭连接。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 18:57:48 +08:00
layue13andClaude Opus 5.5 fc1345d010 perf: 去掉冷路径上的重复开销,并记录未采用的中继批量完成实验
- Message.validateChannel:通道名正则只编译一次(原来每条消息 String.matches 都重新编译),
  长度检查不再分配字节数组
- 后端 OwnedBukkitSessionService:反射查找按接收者类用 ClassValue 缓存(含未找到),
  玩家每次加入不再重复 getMethod
- testing/benchmarks/results/2026-10-22-relay-batch-completion:中继只给每批最后一次写入
  挂完成回调。I/O 线程分配降 22%、中继 lambda 降 97%,但每帧 CPU 只低 2.4% 且范围重叠,
  未达到事先设定的 10% 规则,未采用;补丁随记录保留
- PluginHostTest.placementFailuresOnlyFailTheirOwnRequest:40 ms 超时在负载下可能早于插件
  处理器运行而偶发失败,改为 500 ms 并断言首个请求确实到达插件

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 18:34:36 +08:00
layue13andClaude Opus 5.5 fc02bbdda6 feat: 插件之间的依赖、类共享与类型化服务
- 可选的 META-INF/moonbridge-plugin.yml(id、version、main、dependencies,可选依赖),
  没有描述文件的插件照旧加载
- 加载顺序按依赖图(PluginGraph):依赖先 onLoad/onEnable、后 onDisable;缺少依赖、
  依赖未启用、循环依赖、重复 id、描述文件不合法时给出准确原因并启动失败
- PluginClassLoader 在插件 API 与自身之后查找声明的依赖(含传递依赖);只有声明过的依赖可见
- PluginContext.services():每个类型一个提供方,只对提供方和依赖它的插件可见,随停用注销
- PluginContext.plugins():已加载的带描述文件插件(id、版本、依赖)
- plugins.enabled 可以用 id 作键;数据目录仍按实现类名,无需迁移
- LuckPerms 平台插件的描述文件 id 为 luckperms,版本在构建时写入
- 文档:docs/plugins.md「依赖其他插件」

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 17:31:35 +08:00
layue13 4ed6162faf Merge pull request #7 from layue13/feat/logging
feat: 运维日志策略、玩家与服务器事件日志、滚动日志文件
2026-10-22 17:05:10 +08:00
layue13 e890645ba5 Merge remote-tracking branch 'origin/main' into feat/logging
# Conflicts:
#	proxy/core/src/test/java/dev/moonbridge/app/ProxyConfigurationTest.java
2026-10-22 16:57:55 +08:00
layue13 0abcb37799 Merge pull request #6 from layue13/fix/batch-1-bugs
fix: 修复代码审查发现的一批缺陷
2026-10-22 16:49:42 +08:00
layue13andClaude Opus 5.5 7f68e5682e feat: 运维日志策略、玩家与服务器事件日志、滚动日志文件
- docs/logging.md 规定各级别写什么、永远不写什么,以及新增日志的做法
- core.log.ConnectionLog 统一写玩家(加入、离开、转服、转服失败、未能加入)和服务器
  (注册、地址变更、注销、不可达/恢复)事件,logger 为 moonbridge.players / moonbridge.servers
- LogText 清理对端与插件文本(控制字符、双向文字控制字符、长度上限),防止伪造日志行
- logging.playerAddresses 开关:false 时玩家地址写成 [hidden]
- Session 记录结束原因(先记录者为准),在 closePair 中写离开或未能加入的原因
- 合并的 WARN(ThrottledWarning):连接数上限、插件命令/补全/事件/初次选服过载
- 控制通道:租约过期、注册被拒(按地址和原因去重);插件启用/停用;启动与关闭摘要
- logback:控制台 + logs/latest.log,按天压缩滚动保留 14 天;测试只写控制台

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 16:44:27 +08:00
layue13andClaude Opus 5.5 3f8e14f54d fix: 修复代码审查发现的一批缺陷
- 控制通道:注册字段长度上限统一放在 messaging 的 ControlHandshakeLimits,后端启动时
  按代理的上限校验,不再出现后端接受、代理每次重连都拒绝的配置;后端按阶段记录连接、
  注册与断线失败(每类只记一次,不含对端数据),配置错误时输出具体缺失的键
- 转服登录:握手与 Login Start 的写入合并为 SessionChannels.writeBackendLogin,
  Login Start 无法编码时关闭通道释放已排队的握手,不再泄漏缓冲区
- 命令:插件提供的 CommandSource 的 player()/reply() 不再在宿主锁内调用
- 配置:插件条目没有设置时视为空设置而不是空指针;--validate-config 也检查同一后端名的
  密钥冲突;地址解析不再做 DNS,后端地址按目录使用的 URI 规则校验
- WebSocket:IPv4 映射写法(::ffff:a.b.c.d)的可信代理现在能匹配 IPv4 对端

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 15:40:57 +08:00
layue13 192eca2a46 Merge pull request #5 from layue13/refactor/repo-layout
refactor: 精简仓库根目录与代理发行包
2026-10-22 15:03:28 +08:00
layue13andClaude Opus 5.5 afea023bce build: 代理发行包改为单个可运行的 moonbridge.jar
发行包去掉 bin/ 启动脚本和 lib/ 下的 42 个依赖 jar,改为与其他代理服务端一样
用 java -jar moonbridge.jar 启动:
- proxy-core 用 shadow 打出含全部依赖的 moonbridge.jar(合并 META-INF/services,
  清单写入 Main-Class、Multi-Release 与 Enable-Native-Access: ALL-UNNAMED)
- 泄漏检测默认关闭改由 ProxyMain 在加载 Netty 前设置,显式 -D 仍优先
- 移除不再使用的 application 约定插件
- 安装包检查、烟测与基准脚本改用发行包根目录作 classpath;文档同步

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 15:00:14 +08:00
layue13andClaude Opus 5.5 789648c82f refactor: 仓库根目录按用途分组
- proxy/:core、plugin-api、luckperms 及其上游子模块 vendor/luckperms
- messaging/、backend/ 保持在根目录(messaging 是代理与后端共用的 API)
- build-logic/(原 proxy-build-logic)
- testing/:smoke/ 与 benchmarks/,不进入发行物

Gradle 项目名不变(settings.gradle.kts 映射目录),任务路径与 Maven 坐标照旧。
脚本的仓库根定位、文档与记录中的链接同步更新。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 14:34:01 +08:00
layue13andClaude Opus 5.5 7664c1cf60 build: 代理发行包只保留运行所需内容
发行包根目录去掉 docs/、smoke/results/、benchmarks/results/ 和 backend/,
只剩 bin/、lib/、config/、README(-Pluckperms 时另有 plugins/)。
后端 jar 已由 release 单独放在 build/release/backend/;channel-java8 烟测改为
从 backend/build/libs 取后端 jar。文档同步。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 14:19:36 +08:00
layue13 480999a448 Merge pull request #4 from layue13/refactor/build-and-modules
重构构建与模块:后端 5 合 2、LuckPerms 可选构建、统一 release
2026-10-21 03:26:15 -07:00
layue13 d904410c4b Merge pull request #3 from layue13/feat/websocket-transport
WebSocket 玩家监听(与 TCP 并存)+ 1.7.10 客户端 mod + 文档整理
2026-10-21 03:25:59 -07:00
Claude d836f6c3d3 build: 统一 release 入口,CI 覆盖客户端 mod,文档同步新结构
- 根任务 release:build/release/ 下收集服务器包、后端插件 JAR 与客户端 mod
  (经 client-mod 自身 wrapper 构建,-PskipClientMod 可跳过),附安装位置说明
  docs/release-layout.md
- verify.yml:-Pluckperms check,并新增 client-mod 构建测试 job;
  ci.yml:-Pluckperms check release,上传 build/release/,发布带 -Pluckperms
- gradlew 加可执行位
- README、CLAUDE.md、架构/发布/测试/权限/后端接入文档与 smoke 脚本改用新模块、
  新坐标与发行包 backend/ 目录

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GGL9BudzWm4dUQgBsQw4Qr
2026-10-21 10:13:06 +00:00
Claude f156932f1a refactor(build): 后端 5 个模块合并为 messaging 与 backend,LuckPerms 改为可选构建
模块
- messaging-api + messaging-protocol → messaging(Java 8,消息 API 与线协议)
- backend-channel-client + backend-bukkit-api + backend-bukkit → backend(Java 8;
  jar 即 MoonBridgeBackend Bukkit 插件,内含消息类与控制通道客户端;业务插件
  compileOnly 同一个 jar)
- 包名不变,源码只移动目录;Maven 坐标改为 messaging / backend(破坏性变更)
- 新增 moonbridge.java8-library-conventions 与 moonbridge.publishing-conventions,
  取代各模块复制粘贴的 Java 8 编译和发布配置
- 发行包后端目录由 backend-client/backend-host/backend-api 合为 backend/

LuckPerms
- 只有传入 -Pluckperms 时才 include luckperms-moonbridge 及其 upstream 构建;
  日常 check 不再编译 LuckPerms,permissionAcceptance 与发行包 plugins/ 随该开关
- 根 check/publish 按实际包含的模块聚合

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GGL9BudzWm4dUQgBsQw4Qr
2026-10-21 10:06:20 +00:00
Claude 6a482cfb7d refactor: 并掉 proxy-core 中只有一个类的包
- core.relay.RawRelay → core.session.play(PLAY 数据通路)
- core.net.NetworkTransport → core.session.channel(与后端拨号同处)
- core.forwarding.BungeeLegacyForwarding → core.auth
- core.permission.PermissionService → core.event(会话调用插件运行时的端口)

纯内部移动,不影响插件 API;测试随类移动,文档与 CLAUDE.md 同步。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GGL9BudzWm4dUQgBsQw4Qr
2026-10-21 10:02:13 +00:00
Claude 3e2caf71ff fix(client-mod): wss 只协商 TLS 1.2
对实际 MoonBridge wss 监听实测时发现:JDK 8u261+ 默认提供 TLS 1.3,而
Minecraft 自带的 Netty 4.0.10 SslHandler 无法完成 TLS 1.3 握手,连接在
握手超时后失败。客户端引擎改为只启用 TLSv1.2,并加测试断言;文档说明
TLS 终端不能只开放 TLS 1.3,补充互通实测范围。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GGL9BudzWm4dUQgBsQw4Qr
2026-10-20 21:38:18 +00:00
Claude db2a3fa901 feat: 1.7.10 Forge WebSocket 客户端 mod
client-mod/ 是独立构建(GTNH ExampleMod 模板 + RetroFuturaGradle),coremod +
早期 Mixin,运行时依赖 UniMixins。服务器地址填 ws:// 或 wss:// 时经 WebSocket
连接 MoonBridge,其余地址保持原版 TCP。

- Mixin:ServerAddress 解析、GuiConnecting、NetworkManager.provideLanClient 及其
  ChannelInitializer、OldServerPinger(ws 条目跳过旧版 0xFE ping)
- 使用 MC 自带 Netty 4.0.10 的 WebSocket13 帧编解码与 SslHandler;握手手写,
  Host 头与 SNI 用 URL 主机名,升级完成前缓冲原版写出
- 25 项 JUnit 测试(地址解析、上下文传递、帧适配、管线与本地 WS 服务端交互)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GGL9BudzWm4dUQgBsQw4Qr
2026-10-20 21:34:16 +00:00
Claude 66ef6788f1 feat: 与 TCP 并存的 WebSocket 玩家监听
新增可选 websocket 配置段,在原有 TCP listen 之外再开一个 WebSocket 监听,
供经 CDN 接入的客户端使用;两种入口共用会话、选服、转服和 maxConnections。

- core.websocket:升级握手(可选 TLS)、二进制消息与 Minecraft 字节流互转、
  可信代理真实 IP(X-Forwarded-For 从右取第一个不可信地址 / CF-Connecting-IP 等)
- SessionChannels.clientAddress 统一玩家地址,用于两类准入事件、Mojang 验证 IP
  与 Bungee 转发
- ConnectionGate 支持升级后才加入管线;登录等待守卫放在 WebSocket 适配器之后
- 未升级连接计入 maxConnections,并受 handshakeTimeoutSeconds 约束
- 测试:真实 socket 上 TCP 与 WebSocket 并存登录与转发、分片/合并/Ping、
  在线模式加密与转发 IP、不可信来源、404/文本帧、名额归还、wss 证书加载
- 文档:docs/websocket.md,并更新运行配置、插件、架构与默认配置示例

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GGL9BudzWm4dUQgBsQw4Qr
2026-10-20 21:23:15 +00:00
Claude 4def198cc0 docs: 修正 CI 引用、拆出历史验证记录并统一中文文档
- CLAUDE.md、testing.md、publishing.md 的 .gitea 路径改为实际的 .github/workflows;
  说明 verify.yml 在 PR 上运行 check
- testing.md 中带日期的逐轮结果迁到 docs/records/
- README 精简为简介、快速开始和入口;配置与迁移细节只保留在 operations.md
- channel-messaging-v2.md 更名为 channel-messaging-contract.md,与 transfer-coordination.md 一起译为中文
- benchmarks/results 中两个记录改为日期前缀命名
- 新增 compileBenchmarks 并挂到 check,防止 benchmarks/ 静默失效
- .gitignore 删除不存在的 deployment/ 条目

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GGL9BudzWm4dUQgBsQw4Qr
2026-10-20 21:06:01 +00:00
layue13andClaude Sonnet 5.5 e9a916a192 ci: 统一 workflow 写法,并把 Maven 密钥限定在独立的 publish 任务 [skip ci]
[skip ci]

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 16:44:09 +00:00
layue13andClaude Sonnet 5.5 13a3a15dee Merge branch 'chore/bench-record-and-test-timeout'
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 07:50:43 -07:00
layue13andClaude Sonnet 5.5 c5fe042173 Record session split benchmark and relax a timing-sensitive messaging test
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 07:50:32 -07:00
layue13andClaude Sonnet 5.5 0ad66b6e1d Merge branch 'refactor/split-session': split Session, PluginHost and control classes
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 04:17:16 -07:00
layue13andClaude Sonnet 5.5 aed2d5ca93 Extract ClientControl from Session, narrow package visibility, document layers
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 04:08:31 -07:00
layue13andClaude Sonnet 5.5 fc951bfb7b Split LocalMessaging operations and failure helpers; deduplicate outbound dispatch
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 03:25:20 -07:00
layue13andClaude Sonnet 5.5 765dcffeaa Split BackendChannelClient into session, dispatcher and operation classes
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 03:24:17 -07:00