feat: featured and user-pinned servers on multiplayer list - #188
Conversation
…pinnable own servers Co-authored-by: Gao Yu <gaoyu06@users.noreply.github.com>
There was a problem hiding this comment.
First-pass on this diff only. The PR merged while this review was starting, so this is residual — not a merge gate. Not approving.
Bug: deleting a saved server that shares an address with a featured listing also writes a hide key, so the featured row never comes back. Deleting the same address after the player pinned it does not hide, and the featured row reappears. Hide should run only for promoted-only rows (!servers.contains(selectedServer)).
Missing verification: no tests in the diff (sidecar hide/pin/normalize was claimed as headless smoke but not committed). The new pin row in the detail column has no short-window check; needs one 1.8.9 capture at a small guiHeight before treating that layout as done.
Sent by Cursor Automation: Edge 前置维护
| if (isPromotedEntry(selectedServer)) { | ||
| PromotedServersService.getInstance().hideByAddress(selectedServer.serverIP); | ||
| } | ||
| servers.remove(selectedServer); | ||
| saveServerList(); |
There was a problem hiding this comment.
isPromotedEntry is true for any row styled as featured, including a collapsed own server. Delete then both removes servers.dat and permanently dismisses the featured listing.
The opposite path is already in rebuildServerEntries: a pinned own server is stored as promoted=false, so the same delete skips hide and the featured row comes back.
Gate hide on promoted-only data:
if (!servers.contains(selectedServer)) {
PromotedServersService.getInstance().hideByAddress(selectedServer.serverIP);
}
servers.remove(selectedServer);| if (ownServer) { | ||
| boolean pinned = PromotedServersService.getInstance().isPinned(selectedServer.serverIP); | ||
| float pinY = joinY - 4f - rowH; | ||
| if (UiChrome.buttonClicked(this, x + pad, pinY, width - pad * 2f, rowH, null, | ||
| FPSMaster.i18n.get(pinned ? "multiplayer.unpin" : "multiplayer.pin"), | ||
| UiChrome.Style.DEFAULT, mouseX, mouseY)) { | ||
| PromotedServersService.getInstance().setPinned(selectedServer.serverIP, !pinned); | ||
| rebuildServerEntries(); | ||
| } |
There was a problem hiding this comment.
This inserts a full-width pin row above Join with no remaining-height check. Stats already sit ~127px from the top of the pane; pin + join + edit/delete take ~76px from the bottom. On a short guiHeight (GUI scale 2 / small window) they overlap the stats grid.
Need one 1.8.9 screenshot at a short height before this column is done. If it collides, drop pin onto the edit/delete row or hide it when pinY would enter the stats block.


改动范围
GET /api/v1/launcher/servers作为推荐服置顶;用户可删除后本地不再显示;用户可置顶自建服。UiChrome.badge,用户置顶用keyChip,样式区分。promoted_servers.json,不改servers.datNBT。是否可直接上线
否。阻塞:无 1.8.9 游戏内截图,视觉差与详情栏「置顶」按钮布局未在真实客户端确认。须等已锁定的功能级单次验收。
上线前是否需要 review
是。触发:公共多人界面行为与重要 UI。前置:U3 提交后,与 Nova 视觉、backend 文档一并做一次验收,不另开 Edge-only reviewer。
已跑验证
./gradlew build(含 test,JDK 21):BUILD SUCCESSFUL真实对象证据
MixinGuiMultiplayer→GuiMultiplayerPromotedServersService.fetch()→{API_BASE_URL}/api/v1/launcher/servers.minecraft/FPSMaster Edge/promoted_servers.json依赖
不依赖 backend 新字段或其他 PR。无迁移。
回滚
git revert 77880ff;运行时删除promoted_servers.json即可恢复推荐位显示,不影响servers.dat。