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}
+                    
+
+ )} + + {lpSilent && ( +
+ {t("luckperms_no_reply")} +
+ )} + {/* Operations Feedback */} {formFeedback && (