feature: accesscontrol welcome message

This commit is contained in:
2025-11-03 13:20:21 +08:00
parent 7e03d960bd
commit 2f57d9ab3d
4 changed files with 236 additions and 199 deletions

View File

@@ -117,8 +117,8 @@ const delCommand: Command<AppContext> = {
}, },
}; };
const listCommand: Command<AppContext> = { const listUserCommand: Command<AppContext> = {
name: "list", name: "user",
description: "列出所有玩家及其所在的用户组", description: "列出所有玩家及其所在的用户组",
action: ({ context }) => { action: ({ context }) => {
const config = loadConfig(context.configFilepath)!; const config = loadConfig(context.configFilepath)!;
@@ -134,213 +134,227 @@ const listCommand: Command<AppContext> = {
}, },
}; };
const setCommand: Command<AppContext> = { const listGroupCommand: Command<AppContext> = {
name: "set", name: "group",
description: "显示详细的用户组配置信息",
action: ({ context }) => {
const config = loadConfig(context.configFilepath)!;
let groupsMessage = `管理员组: ${config.adminGroupConfig.groupName}\n`;
groupsMessage += ` 用户: [${config.adminGroupConfig.groupUsers.join(
", ",
)}]\n`;
groupsMessage += ` 允许: ${config.adminGroupConfig.isAllowed}\n`;
groupsMessage += ` 通知: ${config.adminGroupConfig.isNotice}\n\n`;
for (const group of config.usersGroups) {
groupsMessage += `用户组: ${group.groupName}\n`;
groupsMessage += ` 用户: [${(group.groupUsers ?? []).join(", ")}]\n`;
groupsMessage += ` 允许: ${group.isAllowed}\n`;
groupsMessage += ` 通知: ${group.isNotice}\n`;
groupsMessage += "\n";
}
context.print({ text: groupsMessage.trim() });
return Ok.EMPTY;
},
};
const listToastCommand: Command<AppContext> = {
name: "toast",
description: "显示 Toast 配置信息",
action: ({ context }) => {
const config = loadConfig(context.configFilepath)!;
let toastMessage = "默认 Toast 配置:\n";
toastMessage += ` 标题: ${config.welcomeToastConfig.title.text}\n`;
toastMessage += ` 消息: ${config.welcomeToastConfig.msg.text}\n`;
toastMessage += ` 前缀: ${config.welcomeToastConfig.prefix ?? "none"}\n`;
toastMessage += ` 括号: ${config.welcomeToastConfig.brackets ?? "none"}\n`;
toastMessage += ` 括号颜色: ${
config.welcomeToastConfig.bracketColor ?? "none"
}\n\n`;
toastMessage += "警告 Toast 配置:\n";
toastMessage += ` 标题: ${config.warnToastConfig.title.text}\n`;
toastMessage += ` 消息: ${config.warnToastConfig.msg.text}\n`;
toastMessage += ` 前缀: ${config.warnToastConfig.prefix ?? "none"}\n`;
toastMessage += ` 括号: ${config.warnToastConfig.brackets ?? "none"}\n`;
toastMessage += ` 括号颜色: ${
config.warnToastConfig.bracketColor ?? "none"
}`;
context.print({ text: toastMessage });
return Ok.EMPTY;
},
};
const listAllCommand: Command<AppContext> = {
name: "all",
description: "显示基本配置信息概览",
action: ({ context }) => {
const config = loadConfig(context.configFilepath)!;
let allMessage = `检测范围: ${config.detectRange}\n`;
allMessage += `检测间隔: ${config.detectInterval}\n`;
allMessage += `警告间隔: ${config.watchInterval}\n`;
allMessage += `通知次数: ${config.noticeTimes}\n`;
allMessage += `全局欢迎功能: ${config.isWelcome}\n`;
allMessage += `全局警告功能: ${config.isWarn}\n\n`;
allMessage += "使用 'list group' 或 'list toast' 查看详细信息";
context.print({ text: allMessage });
return Ok.EMPTY;
},
};
const listCommand: Command<AppContext> = {
name: "list",
description: "列出玩家、组信息或配置",
subcommands: new Map([
["user", listUserCommand],
["group", listGroupCommand],
["toast", listToastCommand],
["all", listAllCommand],
]),
action: ({ context }) => {
const config = loadConfig(context.configFilepath)!;
let allMessage = `检测范围: ${config.detectRange}\n`;
allMessage += `检测间隔: ${config.detectInterval}\n`;
allMessage += `警告间隔: ${config.watchInterval}\n`;
allMessage += `通知次数: ${config.noticeTimes}\n`;
allMessage += `全局欢迎功能: ${config.isWelcome}\n`;
allMessage += `全局警告功能: ${config.isWarn}\n\n`;
allMessage += "使用 'list group' 或 'list toast' 查看详细信息";
context.print({ text: allMessage });
return Ok.EMPTY;
},
};
const configCommand: Command<AppContext> = {
name: "config",
description: "配置访问控制设置", description: "配置访问控制设置",
args: [ args: [
{ {
name: "option", name: "option",
description: "要设置的选项 (warnInterval, detectInterval, detectRange)", description:
"要设置的选项 (warnInterval, detectInterval, detectRange, noticeTimes, isWelcome, isWarn) 或用户组属性 (<groupName>.isAllowed, <groupName>.isNotice, <groupName>.isWelcome)",
required: true, required: true,
}, },
{ name: "value", description: "要设置的值", required: true }, { name: "value", description: "要设置的值", required: true },
], ],
action: ({ args, context }) => { action: ({ args, context }) => {
const [option, valueStr] = [args.option as string, args.value as string]; const [option, valueStr] = [args.option as string, args.value as string];
const value = parseInt(valueStr);
if (isNaN(value)) {
context.print({ text: `无效的值: ${valueStr}. 必须是一个数字。` });
return Ok.EMPTY;
}
const config = loadConfig(context.configFilepath)!; const config = loadConfig(context.configFilepath)!;
let message = "";
switch (option) { // Check if it's a group property (contains a dot)
case "warnInterval": if (option.includes(".")) {
config.watchInterval = value; const dotIndex = option.indexOf(".");
message = `已设置警告间隔为 ${value}`; const groupName = option.substring(0, dotIndex);
break; const property = option.substring(dotIndex + 1);
case "detectInterval":
config.detectInterval = value; let groupConfig: UserGroupConfig | undefined;
message = `已设置检测间隔为 ${value}`; if (groupName === "admin") {
break; groupConfig = config.adminGroupConfig;
case "detectRange": } else {
config.detectRange = value; groupConfig = config.usersGroups.find((g) => g.groupName === groupName);
message = `已设置检测范围为 ${value}`; }
break;
default: if (!groupConfig) {
context.print({ text: `用户组 ${groupName} 未找到` });
return Ok.EMPTY;
}
const boolValue = parseBoolean(valueStr);
if (boolValue === undefined) {
context.print({ context.print({
text: `未知选项: ${option}. 可用选项: warnInterval, detectInterval, detectRange`, text: `无效的布尔值: ${valueStr}. 请使用 'true' 或 'false'.`,
}); });
return Ok.EMPTY; return Ok.EMPTY;
} }
saveConfig(config, context.configFilepath); let message = "";
context.reloadConfig(); switch (property) {
context.print({ text: message }); case "isAllowed":
return Ok.EMPTY; groupConfig.isAllowed = boolValue;
}, message = `已设置 ${groupName}.isAllowed 为 ${boolValue}`;
}; break;
case "isNotice":
groupConfig.isNotice = boolValue;
message = `已设置 ${groupName}.isNotice 为 ${boolValue}`;
break;
case "isWelcome":
groupConfig.isWelcome = boolValue;
message = `已设置 ${groupName}.isWelcome 为 ${boolValue}`;
break;
default:
context.print({
text: `未知属性: ${property}. 可用属性: isAllowed, isNotice, isWelcome`,
});
return Ok.EMPTY;
}
const editGroupCommand: Command<AppContext> = { saveConfig(config, context.configFilepath);
name: "group", context.reloadConfig();
description: "编辑用户组属性", context.print({ text: message });
args: [ return Ok.EMPTY;
{
name: "groupName",
description: "要编辑的用户组名称",
required: true,
},
{
name: "property",
description: "要更改的属性 (isAllowed, isNotice)",
required: true,
},
{ name: "value", description: "新值 (true/false)", required: true },
],
action: ({ args, context }) => {
const [groupName, property, valueStr] = [
args.groupName as string,
args.property as string,
args.value as string,
];
const config = loadConfig(context.configFilepath)!;
let groupConfig: UserGroupConfig | undefined;
if (groupName === "admin") {
groupConfig = config.adminGroupConfig;
} else { } else {
groupConfig = config.usersGroups.find((g) => g.groupName === groupName); // Handle basic configuration options
} let message = "";
if (!groupConfig) { // Check if it's a boolean option
context.print({ text: `用户组 ${groupName} 未找到` }); if (option === "isWelcome" || option === "isWarn") {
return Ok.EMPTY; const boolValue = parseBoolean(valueStr);
} if (boolValue === undefined) {
context.print({
const boolValue = parseBoolean(valueStr); text: `无效的布尔值: ${valueStr}. 请使用 'true' 或 'false'.`,
if (boolValue === undefined) { });
context.print({ return Ok.EMPTY;
text: `无效的布尔值: ${valueStr}. 请使用 'true' 或 'false'.`, }
});
return Ok.EMPTY; switch (option) {
} case "isWelcome":
config.isWelcome = boolValue;
let message = ""; message = `已设置全局欢迎功能为 ${boolValue}`;
switch (property) { break;
case "isAllowed": case "isWarn":
groupConfig.isAllowed = boolValue; config.isWarn = boolValue;
message = `已设置 ${groupName}.isAllowed ${boolValue}`; message = `已设置全局警告功能${boolValue}`;
break; break;
case "isNotice": }
groupConfig.isNotice = boolValue; } else {
message = `已设置 ${groupName}.isNotice 为 ${boolValue}`; // Handle numeric options
break; const value = parseInt(valueStr);
default:
context.print({ if (isNaN(value)) {
text: `未知属性: ${property}. 可用属性: isAllowed, isNotice`, context.print({ text: `无效的值: ${valueStr}. 必须是一个数字。` });
}); return Ok.EMPTY;
return Ok.EMPTY; }
}
switch (option) {
saveConfig(config, context.configFilepath); case "warnInterval":
context.reloadConfig(); config.watchInterval = value;
context.print({ text: message }); message = `已设置警告间隔为 ${value}`;
return Ok.EMPTY; break;
}, case "detectInterval":
}; config.detectInterval = value;
message = `已设置检测间隔为 ${value}`;
const editCommand: Command<AppContext> = { break;
name: "edit", case "detectRange":
description: "编辑各项配置", config.detectRange = value;
subcommands: new Map([["group", editGroupCommand]]), message = `已设置检测范围为 ${value}`;
}; break;
case "noticeTimes":
const showConfigCommand: Command<AppContext> = { config.noticeTimes = value;
name: "showconfig", message = `已设置通知次数为 ${value}`;
description: "显示配置", break;
options: new Map([ default:
[ context.print({
"type", text: `未知选项: ${option}. 可用选项: warnInterval, detectInterval, detectRange, noticeTimes, isWelcome, isWarn 或 <groupName>.isAllowed, <groupName>.isNotice, <groupName>.isWelcome`,
{ });
name: "type", return Ok.EMPTY;
description: "要显示的配置类型 (groups, toast, all)",
required: false,
defaultValue: "all",
},
],
]),
action: ({ options, context }) => {
const type = options.type as string;
const config = loadConfig(context.configFilepath)!;
let message = "";
switch (type) {
case "groups": {
let groupsMessage = `管理员组: ${config.adminGroupConfig.groupName}\n`;
groupsMessage += ` 用户: [${config.adminGroupConfig.groupUsers.join(
", ",
)}]\n`;
groupsMessage += ` 允许: ${config.adminGroupConfig.isAllowed}\n`;
groupsMessage += ` 通知: ${config.adminGroupConfig.isNotice}\n\n`;
for (const group of config.usersGroups) {
groupsMessage += `用户组: ${group.groupName}\n`;
groupsMessage += ` 用户: [${(group.groupUsers ?? []).join(", ")}]\n`;
groupsMessage += ` 允许: ${group.isAllowed}\n`;
groupsMessage += ` 通知: ${group.isNotice}\n`;
groupsMessage += "\n";
} }
message = groupsMessage.trim();
break;
} }
case "toast": { saveConfig(config, context.configFilepath);
let toastMessage = "默认 Toast 配置:\n"; context.reloadConfig();
toastMessage += ` 标题: ${config.welcomeToastConfig.title.text}\n`; context.print({ text: message });
toastMessage += ` 消息: ${config.welcomeToastConfig.msg.text}\n`; return Ok.EMPTY;
toastMessage += ` 前缀: ${
config.welcomeToastConfig.prefix ?? "none"
}\n`;
toastMessage += ` 括号: ${
config.welcomeToastConfig.brackets ?? "none"
}\n`;
toastMessage += ` 括号颜色: ${
config.welcomeToastConfig.bracketColor ?? "none"
}\n\n`;
toastMessage += "警告 Toast 配置:\n";
toastMessage += ` 标题: ${config.warnToastConfig.title.text}\n`;
toastMessage += ` 消息: ${config.warnToastConfig.msg.text}\n`;
toastMessage += ` 前缀: ${config.warnToastConfig.prefix ?? "none"}\n`;
toastMessage += ` 括号: ${
config.warnToastConfig.brackets ?? "none"
}\n`;
toastMessage += ` 括号颜色: ${
config.warnToastConfig.bracketColor ?? "none"
}`;
message = toastMessage;
break;
}
case "all": {
let allMessage = `检测范围: ${config.detectRange}\n`;
allMessage += `检测间隔: ${config.detectInterval}\n`;
allMessage += `警告间隔: ${config.watchInterval}\n\n`;
allMessage +=
"使用 'showconfig --type groups' 或 'showconfig --type toast' 查看详细信息";
message = allMessage;
break;
}
default:
message = `无效类型: ${type}. 可用类型: groups, toast, all`;
break;
} }
context.print({ text: message });
return Ok.EMPTY;
}, },
}; };
@@ -352,9 +366,7 @@ const rootCommand: Command<AppContext> = {
["add", addCommand], ["add", addCommand],
["del", delCommand], ["del", delCommand],
["list", listCommand], ["list", listCommand],
["set", setCommand], ["config", configCommand],
["edit", editCommand],
["showconfig", showConfigCommand],
]), ]),
action: ({ context }) => { action: ({ context }) => {
context.print([ context.print([
@@ -383,6 +395,6 @@ const rootCommand: Command<AppContext> = {
export function createAccessControlCli(context: AppContext) { export function createAccessControlCli(context: AppContext) {
return createCli(rootCommand, { return createCli(rootCommand, {
globalContext: context, globalContext: context,
writer: (msg) => context.print(msg), writer: (msg) => context.print({ text: msg }),
}); });
} }

View File

@@ -21,6 +21,7 @@ interface AccessConfig {
watchInterval: number; watchInterval: number;
noticeTimes: number; noticeTimes: number;
detectRange: number; detectRange: number;
isWelcome: boolean;
isWarn: boolean; isWarn: boolean;
adminGroupConfig: UserGroupConfig; adminGroupConfig: UserGroupConfig;
welcomeToastConfig: ToastConfig; welcomeToastConfig: ToastConfig;
@@ -35,12 +36,13 @@ const defaultConfig: AccessConfig = {
watchInterval: 10, watchInterval: 10,
noticeTimes: 2, noticeTimes: 2,
isWarn: false, isWarn: false,
isWelcome: true,
adminGroupConfig: { adminGroupConfig: {
groupName: "Admin", groupName: "Admin",
groupUsers: ["Selcon"], groupUsers: ["Selcon"],
isAllowed: true, isAllowed: true,
isNotice: true, isNotice: true,
isWelcome: true, isWelcome: false,
}, },
usersGroups: [ usersGroups: [
{ {
@@ -50,6 +52,13 @@ const defaultConfig: AccessConfig = {
isNotice: true, isNotice: true,
isWelcome: false, isWelcome: false,
}, },
{
groupName: "TU",
groupUsers: [],
isAllowed: true,
isNotice: false,
isWelcome: false,
},
{ {
groupName: "VIP", groupName: "VIP",
groupUsers: [], groupUsers: [],

View File

@@ -2,7 +2,6 @@ import { CCLog, DAY, LogLevel } from "@/lib/ccLog";
import { ToastConfig, UserGroupConfig, loadConfig } from "./config"; import { ToastConfig, UserGroupConfig, loadConfig } from "./config";
import { createAccessControlCli } from "./cli"; import { createAccessControlCli } from "./cli";
import { launchAccessControlTUI } from "./tui"; import { launchAccessControlTUI } from "./tui";
import * as peripheralManager from "../lib/PeripheralManager";
import { deepCopy } from "@/lib/common"; import { deepCopy } from "@/lib/common";
import { ReadWriteLock } from "@/lib/mutex/ReadWriteLock"; import { ReadWriteLock } from "@/lib/mutex/ReadWriteLock";
import { ChatManager } from "@/lib/ChatManager"; import { ChatManager } from "@/lib/ChatManager";
@@ -15,7 +14,7 @@ const args = [...$vararg];
const logger = new CCLog("accesscontrol.log", { const logger = new CCLog("accesscontrol.log", {
printTerminal: true, printTerminal: true,
logInterval: DAY, logInterval: DAY,
outputMinLevel: LogLevel.Debug, outputMinLevel: LogLevel.Info,
}); });
// Load Config // Load Config
@@ -278,6 +277,8 @@ function mainLoop() {
isNotice: false, isNotice: false,
isWelcome: false, isWelcome: false,
}; };
// Get user group config
for (const userGroupConfig of config.usersGroups) { for (const userGroupConfig of config.usersGroups) {
if (userGroupConfig.groupUsers == undefined) continue; if (userGroupConfig.groupUsers == undefined) continue;
if (!userGroupConfig.groupUsers.includes(player)) continue; if (!userGroupConfig.groupUsers.includes(player)) continue;
@@ -286,21 +287,27 @@ function mainLoop() {
logger.info( logger.info(
`${groupConfig.groupName} ${player} appear at ${playerInfo?.x}, ${playerInfo?.y}, ${playerInfo?.z}`, `${groupConfig.groupName} ${player} appear at ${playerInfo?.x}, ${playerInfo?.y}, ${playerInfo?.z}`,
); );
if (userGroupConfig.isWelcome)
sendMessage(config.welcomeToastConfig, player, {
playerName: player,
groupName: groupConfig.groupName,
info: playerInfo,
});
break; break;
} }
if (config.adminGroupConfig.isWelcome)
sendMessage(config.welcomeToastConfig, player, {
playerName: player,
groupName: groupConfig.groupName,
info: playerInfo,
});
if (groupConfig.isAllowed) continue; if (groupConfig.isAllowed) continue;
logger.warn( logger.warn(
`${groupConfig.groupName} ${player} appear at ${playerInfo?.x}, ${playerInfo?.y}, ${playerInfo?.z}`, `${groupConfig.groupName} ${player} appear at ${playerInfo?.x}, ${playerInfo?.y}, ${playerInfo?.z}`,
); );
if (config.isWelcome)
sendMessage(config.welcomeToastConfig, player, {
playerName: player,
groupName: groupConfig.groupName,
info: playerInfo,
});
if (config.isWarn) sendWarn(player); if (config.isWarn) sendWarn(player);
gWatchPlayersInfo = [ gWatchPlayersInfo = [
...gWatchPlayersInfo, ...gWatchPlayersInfo,

View File

@@ -323,6 +323,15 @@ const AccessControlTUI = () => {
onChange: (checked) => setConfig("isWarn", checked), onChange: (checked) => setConfig("isWarn", checked),
}), }),
), ),
div(
{ class: "flex flex-row" },
label({}, "Is Welcome:"),
input({
type: "checkbox",
checked: () => config().isWelcome ?? false,
onChange: (checked) => setConfig("isWelcome", checked),
}),
),
); );
}; };