diff --git a/panel/src/i18n/resources/en-US/servers.json b/panel/src/i18n/resources/en-US/servers.json
index c66aeaa..778fcdc 100644
--- a/panel/src/i18n/resources/en-US/servers.json
+++ b/panel/src/i18n/resources/en-US/servers.json
@@ -159,6 +159,8 @@
"luckperms_revert_success": "Action reverted successfully!",
"luckperms_presets": "Presets",
"luckperms_no_parent_groups": "No parent groups assigned",
+ "luckperms_no_reply": "The server returned no parseable data — some LuckPerms versions do not reply over RCON, so the group/permission lists below may be incomplete. Grants and revocations still take effect.",
+ "luckperms_no_output": "(the server returned no output)",
"luckperms_global": "global",
"luckperms_no_perms": "No explicit permission nodes assigned",
"luckperms_rcon_output": "RCON Console Output",
diff --git a/panel/src/i18n/resources/zh-CN/servers.json b/panel/src/i18n/resources/zh-CN/servers.json
index b64f837..c91a6fc 100644
--- a/panel/src/i18n/resources/zh-CN/servers.json
+++ b/panel/src/i18n/resources/zh-CN/servers.json
@@ -159,6 +159,8 @@
"luckperms_revert_success": "已成功撤销该操作!",
"luckperms_presets": "预设",
"luckperms_no_parent_groups": "未分配任何父组",
+ "luckperms_no_reply": "服务器没有返回可解析的数据——部分 LuckPerms 版本不通过 RCON 回包,下面的用户组/权限列表可能不准确;授予与撤销操作仍然会实际生效。",
+ "luckperms_no_output": "(服务器未返回输出)",
"luckperms_global": "全局",
"luckperms_no_perms": "尚未分配任何权限节点",
"luckperms_rcon_output": "RCON 控制台输出",
diff --git a/panel/src/lib/api.ts b/panel/src/lib/api.ts
index a4a30ab..293bd70 100644
--- a/panel/src/lib/api.ts
+++ b/panel/src/lib/api.ts
@@ -245,6 +245,7 @@ export const api = {
player: string;
groups: string[];
permissions: { node: string; value: boolean; world?: string }[];
+ output: string;
}>("GET", `/servers/${name}/access/luckperms/${player}`),
accessPermission: (
diff --git a/panel/src/pages/ServerLuckPerms.tsx b/panel/src/pages/ServerLuckPerms.tsx
index e2d9155..de61302 100644
--- a/panel/src/pages/ServerLuckPerms.tsx
+++ b/panel/src/pages/ServerLuckPerms.tsx
@@ -88,6 +88,18 @@ export function ServerLuckPerms() {
[name, selectedPlayer]
);
+ // LuckPerms does not reply over RCON (its commands finish asynchronously, after
+ // the response is flushed) — verified live on 5.5.85: every `lp` command
+ // returns an empty body while `list`/`plugins` answer normally. A silent,
+ // entry-less reply therefore means "could not read", NOT "no groups / no
+ // permissions": the two projection panels must not claim the latter on their
+ // own. The writes still work, so the page keeps offering them.
+ const lpSilent =
+ !!lpInfo &&
+ !(lpInfo.output ?? "").trim() &&
+ (lpInfo.groups?.length ?? 0) === 0 &&
+ (lpInfo.permissions?.length ?? 0) === 0;
+
// Form State
const [groupNameInput, setGroupNameInput] = useState("");
const [permNodeInput, setPermNodeInput] = useState("");
@@ -135,7 +147,7 @@ export function ServerLuckPerms() {
action: "add",
target: groupName,
status: "success",
- output: res.output || `[RCON] parent add ${groupName}`,
+ output: res.output || t("luckperms_no_output"),
});
reloadLp();
} catch (err) {
@@ -157,7 +169,7 @@ export function ServerLuckPerms() {
action: "remove",
target: groupName,
status: "success",
- output: res.output || `[RCON] parent remove ${groupName}`,
+ output: res.output || t("luckperms_no_output"),
});
reloadLp();
} catch (err) {
@@ -194,7 +206,7 @@ export function ServerLuckPerms() {
value: permValueInput,
world: world || undefined,
status: "success",
- output: res.output || `[RCON] permission set ${node}`,
+ output: res.output || t("luckperms_no_output"),
});
setPermNodeInput("");
setPermWorldInput("");
@@ -219,7 +231,7 @@ export function ServerLuckPerms() {
target: node,
world: world || undefined,
status: "success",
- output: res.output || `[RCON] permission unset ${node}`,
+ output: res.output || t("luckperms_no_output"),
});
reloadLp();
} catch (err) {
@@ -395,6 +407,30 @@ export function ServerLuckPerms() {
+ {/* Ground truth: the raw RCON reply behind the two projection panels.
+ The parse is LuckPerms-format-specific — on a server without the
+ plugin it yields zero entries, and without this disclosure the
+ panels would present that as "no groups / no permissions" while
+ the real reply ("Unknown or incomplete command…") stays invisible.
+ Same disclosure the whitelist/ban/online rosters carry. */}
+ {lpInfo?.output?.trim() && (
+
+ ▶
+ {t("luckperms_rcon_output")}
+
+
+ {lpInfo.output}
+
+