From 2a696b4854ad2c9eadf25fd126c49e0f9a5016e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=AD=B1=E5=82=91?= Date: Sun, 5 Mar 2023 17:10:03 +0800 Subject: [PATCH] Implement op execution command Add in-game online and offline broadcast --- README.md | 36 ++++++- .../jie65535/openchat/OpenChatConfig.java | 43 +++++++- .../jie65535/openchat/OpenChatSystem.java | 98 ++++++++++++++----- .../openchat/commands/ChatServerCommands.java | 19 +++- 4 files changed, 163 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 3ebec67..435bbc1 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,10 @@ - `/serverchat limit <次每分钟>` 设置发消息频率限制 - `/serverchat reload` 重载配置文件 - `/serverchat group ` 设置互联群号 +- `/serverchat op|deop ` 设置或解除管理员 + - 被设置为管理的账号可以在指定群内直接用管理前缀执行命令 + - 命令前缀可在配置文件中设置 `adminPrefix` ,默认为 `/`,例 `/sc ban @10002` + - 目前在群内执行命令暂时没有回复,因为控制台执行过程只会log到控制台,不好捕获 `/serverchat` 可用别名 `/sc`,例如 `/sc ban @xxx` @@ -57,6 +61,13 @@ 建议使用 `Android Watch` 协议登录(在 `device.json` 中 `"protocol": 5` 修改为 `"protocol": 2` ) +### 群服互联参考流程 +1. 装好插件启动后,记录下首次生成的 `Token`,或者自己填写一个 `Token` +2. 下载 [go-cqhttp](https://github.com/Mrs4s/go-cqhttp) 并初始化配置 +3. 在 `access-token: ''` 填写前面所述的 `Token` 内容 +4. 在 `ws-reverse` 选项下的 `universal` 填写GC的服务器地址加路径,例如 `ws://127.0.0.1:443/openchat` +5. 配置你的Bot账号和登录协议,建议使用 `Android Watch` 登录。具体参考文档 [配置](https://docs.go-cqhttp.org/guide/config.html)。 + --- ## 插件配置 @@ -139,8 +150,11 @@ // 是否接收群消息并发送到游戏里 "isSendToGame": true, - // // 管理员账号 - // "adminId": 0, + // 管理员账号 + "adminIds": [0], + + // 管理员执行命令前缀 + "adminPrefix": "/", // 是否启用登录消息 // 当玩家登录服务器时,发送消息通知到群里 @@ -151,6 +165,15 @@ // {uid} 为玩家UID "loginMessageFormat": "{nickName}({uid}) 加入了服务器", + // 是否启用登录消息 + // 当玩家登录服务器时,发送消息通知到群里 + "sendLoginMessageToGame": true, + + // 玩家登录服务器消息格式 + // {nickName} 为玩家昵称 + // {uid} 为玩家UID + "loginMessageFormatInGame": "{nickName}({uid}) 加入了游戏", + // 是否启用登出消息 // 当玩家离开服务器时,发送消息通知到群里 "sendLogoutMessageToBot": true, @@ -159,6 +182,15 @@ // {nickName} 为玩家昵称 // {uid} 为玩家UID "logoutMessageFormat": "{nickName}({uid}) 离开了服务器", + + // 是否启用登出消息 + // 当玩家离开服务器时,发送消息通知到群里 + "sendLogoutMessageToGame": true, + + // 玩家登出服务器消息格式 + // {nickName} 为玩家昵称 + // {uid} 为玩家UID + "logoutMessageFormatInGame": "{nickName}({uid}) 离开了游戏", } ``` diff --git a/src/main/java/com/github/jie65535/openchat/OpenChatConfig.java b/src/main/java/com/github/jie65535/openchat/OpenChatConfig.java index 9c70084..394d96c 100644 --- a/src/main/java/com/github/jie65535/openchat/OpenChatConfig.java +++ b/src/main/java/com/github/jie65535/openchat/OpenChatConfig.java @@ -17,6 +17,9 @@ */ package com.github.jie65535.openchat; +import java.util.ArrayList; +import java.util.List; + public class OpenChatConfig { /** @@ -127,10 +130,16 @@ public class OpenChatConfig { */ public boolean isSendToGame = true; -// /** -// * 管理员账号 -// */ -// public Long adminId = 0L; + /** + * 管理员账号列表 + * 所有来自管理员的消息,如果和命令前缀匹配,将作为控制台命令执行 + */ + public ArrayList adminIds = new ArrayList<>(List.of(0L)); + + /** + * 管理员执行命令前缀 + */ + public String adminPrefix = "/"; /** * 是否启用登录消息 @@ -145,6 +154,19 @@ public class OpenChatConfig { */ public String loginMessageFormat = "{nickName}({uid}) 加入了服务器"; + /** + * 是否启用登录消息 + * 当玩家登录服务器时,发送消息通知到游戏里 + */ + public boolean sendLoginMessageToGame = true; + + /** + * 玩家登录服务器消息格式(游戏内) + * {nickName} 为玩家昵称 + * {uid} 为玩家UID + */ + public String loginMessageFormatInGame = "{nickName}({uid}) 加入了游戏"; + /** * 是否启用登出消息 * 当玩家离开服务器时,发送消息通知到群里 @@ -157,4 +179,17 @@ public class OpenChatConfig { * {uid} 为玩家UID */ public String logoutMessageFormat = "{nickName}({uid}) 离开了服务器"; + + /** + * 是否启用登出消息 + * 当玩家登录服务器时,发送消息通知到游戏里 + */ + public boolean sendLogoutMessageToGame = true; + + /** + * 玩家登出服务器消息格式(游戏内) + * {nickName} 为玩家昵称 + * {uid} 为玩家UID + */ + public String logoutMessageFormatInGame = "{nickName}({uid}) 离开了游戏"; } diff --git a/src/main/java/com/github/jie65535/openchat/OpenChatSystem.java b/src/main/java/com/github/jie65535/openchat/OpenChatSystem.java index a4ca5ef..e80bf0b 100644 --- a/src/main/java/com/github/jie65535/openchat/OpenChatSystem.java +++ b/src/main/java/com/github/jie65535/openchat/OpenChatSystem.java @@ -20,6 +20,7 @@ package com.github.jie65535.openchat; import com.github.jie65535.minionebot.MiniOneBot; import com.github.jie65535.minionebot.events.GroupMessage; import emu.grasscutter.GameConstants; +import emu.grasscutter.command.CommandMap; import emu.grasscutter.game.chat.ChatSystem; import emu.grasscutter.game.player.Player; import emu.grasscutter.server.event.player.PlayerJoinEvent; @@ -65,11 +66,22 @@ public class OpenChatSystem extends ChatSystem { * @param event 事件 */ public void onPlayerJoin(PlayerJoinEvent event) { - if (!plugin.getConfig().sendLoginMessageToBot || plugin.getConfig().groupId < 1) return; var player = event.getPlayer(); - miniOneBot.sendGroupMessage(plugin.getConfig().groupId, plugin.getConfig().loginMessageFormat - .replace("{nickName}", player.getNickname()) - .replace("{uid}", String.valueOf(player.getUid()))); + // 发送上线消息到群里 + if (plugin.getConfig().sendLoginMessageToBot && plugin.getConfig().groupId >= 1) { + miniOneBot.sendGroupMessage(plugin.getConfig().groupId, plugin.getConfig().loginMessageFormat + .replace("{nickName}", player.getNickname()) + .replace("{uid}", String.valueOf(player.getUid()))); + } + + // 发送上线消息到游戏 + if (plugin.getConfig().sendLoginMessageToGame) { + broadcastChatMessage(plugin.getConfig().loginMessageFormatInGame + .replace("{nickName}", player.getNickname()) + .replace("{uid}", String.valueOf(player.getUid())), + player.getUid() + ); + } } /** @@ -87,11 +99,21 @@ public class OpenChatSystem extends ChatSystem { super.clearHistoryOnLogout(player); hasHistory.remove(player.getUid()); - // 发送离线消息 - if (!plugin.getConfig().sendLogoutMessageToBot || plugin.getConfig().groupId < 1) return; - miniOneBot.sendGroupMessage(plugin.getConfig().groupId, plugin.getConfig().logoutMessageFormat - .replace("{nickName}", player.getNickname()) - .replace("{uid}", String.valueOf(player.getUid()))); + // 发送离线消息到群里 + if (plugin.getConfig().sendLogoutMessageToBot && plugin.getConfig().groupId >= 1) { + miniOneBot.sendGroupMessage(plugin.getConfig().groupId, plugin.getConfig().logoutMessageFormat + .replace("{nickName}", player.getNickname()) + .replace("{uid}", String.valueOf(player.getUid()))); + } + + // 发送离线消息到游戏 + if (plugin.getConfig().sendLogoutMessageToGame) { + broadcastChatMessage(plugin.getConfig().logoutMessageFormatInGame + .replace("{nickName}", player.getNickname()) + .replace("{uid}", String.valueOf(player.getUid())), + player.getUid() + ); + } } /** @@ -196,19 +218,15 @@ public class OpenChatSystem extends ChatSystem { .replace("{message}", message); // 转发给其它玩家 - for (Player p : getServer().getPlayers().values()) { - // 将消息发送给除了自己以外所有未关闭聊天的玩家 - if (p != player && !plugin.getData().offChatPlayers.contains(p.getUid())) { - p.dropMessage(formattedMessage); - } - } + broadcastChatMessage(formattedMessage, player.getUid()); // 转发到机器人 - if (!plugin.getConfig().isSendToBot || plugin.getConfig().groupId < 1) return; - miniOneBot.sendGroupMessage(plugin.getConfig().groupId, plugin.getConfig().gameToGroupFormat - .replace("{nickName}", player.getNickname()) - .replace("{uid}", String.valueOf(player.getUid())) - .replace("{message}", message)); + if (plugin.getConfig().isSendToBot && plugin.getConfig().groupId >= 1) { + miniOneBot.sendGroupMessage(plugin.getConfig().groupId, plugin.getConfig().gameToGroupFormat + .replace("{nickName}", player.getNickname()) + .replace("{uid}", String.valueOf(player.getUid())) + .replace("{message}", message)); + } } /** @@ -217,16 +235,34 @@ public class OpenChatSystem extends ChatSystem { * @param event 群消息事件 */ private void onGroupMessage(GroupMessage event) { - if (!plugin.getConfig().isSendToGame - || plugin.getConfig().groupId < 1 - || event.groupId() != plugin.getConfig().groupId - ) return; + if (plugin.getConfig().groupId < 1 || event.groupId() != plugin.getConfig().groupId) return; + + // 判断是否管理员发送的消息 + if (plugin.getConfig().adminIds.contains(event.senderId()) + && !plugin.getConfig().adminPrefix.isEmpty() // 判断是否符合命令前缀 + && event.message().startsWith(plugin.getConfig().adminPrefix) + ) { + try { + logger.info("Command used by op [{}({})]: {}", event.senderCardOrNickname(), event.senderId(), event.message()); + // 尝试执行管理员命令 + CommandMap.getInstance().invoke(null, null, + event.message().substring(plugin.getConfig().adminPrefix.length())); + } catch (Exception ex) { + logger.error("Administrator command execution failed", ex); + } + return; + } + + // 检查开关 + if (!plugin.getConfig().isSendToGame) return; // log messages if (plugin.getConfig().logChat) { logger.info("[MiniOneBot] {}: \"{}\"", event.senderCardOrNickname(), event.message()); } + + // 发送给所有玩家 broadcastChatMessage(plugin.getConfig().groupToGameFormat .replace("{id}", String.valueOf(event.senderId())) .replace("{name}", event.senderCardOrNickname()) @@ -238,9 +274,19 @@ public class OpenChatSystem extends ChatSystem { * * @param message 纯文本消息 */ - public void broadcastChatMessage(String message) { + private void broadcastChatMessage(String message) { + broadcastChatMessage(message, 0); + } + + /** + * 广播聊天消息给除了指定玩家外所有玩家(未开启聊天玩家除外) + * + * @param message 纯文本消息 + * @param exceptId 排除在外的Uid + */ + private void broadcastChatMessage(String message, int exceptId) { for (Player p : getServer().getPlayers().values()) { - if (!plugin.getData().offChatPlayers.contains(p.getUid())) { + if (p.getUid() != exceptId && !plugin.getData().offChatPlayers.contains(p.getUid())) { p.dropMessage(message); } } diff --git a/src/main/java/com/github/jie65535/openchat/commands/ChatServerCommands.java b/src/main/java/com/github/jie65535/openchat/commands/ChatServerCommands.java index e310b58..f0ea684 100644 --- a/src/main/java/com/github/jie65535/openchat/commands/ChatServerCommands.java +++ b/src/main/java/com/github/jie65535/openchat/commands/ChatServerCommands.java @@ -33,6 +33,7 @@ import java.util.List; "limit ", "reload", "group ", + "op|deop ", }, permission = "server.chat", permissionTargeted = "server.chat.others", @@ -112,7 +113,7 @@ public class ChatServerCommands implements CommandHandler { var groupId = 0L; try { groupId = Long.parseLong(args.get(1)); - } catch (NumberFormatException ignored) { + } catch (Exception ignored) { sendUsageMessage(sender); return; } @@ -120,6 +121,22 @@ public class ChatServerCommands implements CommandHandler { plugin.saveConfig(); CommandHandler.sendMessage(sender, "OK"); } + case "op", "deop" -> { + var adminId = 0L; + try { + adminId = Long.parseLong(args.get(1)); + } catch (Exception ignored) { + sendUsageMessage(sender); + return; + } + if (subCommand.equals("op")) { + plugin.getConfig().adminIds.add(adminId); + } else { + plugin.getConfig().adminIds.remove(adminId); + } + plugin.saveConfig(); + CommandHandler.sendMessage(sender, "OK"); + } default -> sendUsageMessage(sender); } }