mirror of
https://github.com/jie65535/gc-openchat-plugin.git
synced 2025-12-15 18:31:33 +08:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 01a2feec03 | |||
| 04b8d2dc77 | |||
| 4129eaa13e | |||
| dc90a17824 | |||
| e795c5a9c4 | |||
| 28456bb179 | |||
| 397cf392f5 |
@@ -45,7 +45,6 @@ Server command (requires `server.chat.others` permissions) :
|
|||||||
- `/serverchat op|deop <userId(QQ)>` Set or remove op
|
- `/serverchat op|deop <userId(QQ)>` Set or remove op
|
||||||
- The account set as op can directly execute commands with the admin prefix in the specified group
|
- The account set as op can directly execute commands with the admin prefix in the specified group
|
||||||
- The command prefix can be set in the configuration file `adminPrefix`, the default is `/`, for example `/sc ban @10002`
|
- The command prefix can be set in the configuration file `adminPrefix`, the default is `/`, for example `/sc ban @10002`
|
||||||
- At present, there is no reply when executing commands in the group, because the console execution process will only log to the console, which is not easy to capture
|
|
||||||
|
|
||||||
`/serverchat` can be aliased as `/sc`
|
`/serverchat` can be aliased as `/sc`
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
在游戏内与服务器账号对话,相当于发送到世界频道,服务器内所有玩家均可收到消息。
|
在游戏内与服务器账号对话,相当于发送到世界频道,服务器内所有玩家均可收到消息。
|
||||||
|
|
||||||
## TODO List
|
## 功能列表
|
||||||
- [x] 玩家间聊天
|
- [x] 玩家间聊天
|
||||||
- [x] 聊天管理命令
|
- [x] 聊天管理命令
|
||||||
- [x] 发言频率限制
|
- [x] 发言频率限制
|
||||||
@@ -72,12 +72,10 @@
|
|||||||
7. 在GC中使用 `/sc op <userId(QQ)>` 来设置管理员账号
|
7. 在GC中使用 `/sc op <userId(QQ)>` 来设置管理员账号
|
||||||
8. 现在,理论上已经完成了群服互联,在群里可以看到玩家上下线和聊天,同时玩家也可以在游戏里看到群里聊天,
|
8. 现在,理论上已经完成了群服互联,在群里可以看到玩家上下线和聊天,同时玩家也可以在游戏里看到群里聊天,
|
||||||
你还可以在群里用默认前缀 `/` 来执行命令,
|
你还可以在群里用默认前缀 `/` 来执行命令,
|
||||||
但是暂时**不会**回复结果,你可能需要自己看控制台来查看执行结果。
|
|
||||||
|
|
||||||
|
|
||||||
_值得注意的是,本插件支持的是 [OneBot-v11](https://github.com/botuniverse/onebot-11) 协议,理论上所有支持OneBot-v11 [反向WebSocket](https://github.com/botuniverse/onebot-11/blob/master/communication/ws-reverse.md) 的机器人框架都可以连接,不仅限于cqhttp。_
|
_值得注意的是,本插件支持的是 [OneBot-v11](https://github.com/botuniverse/onebot-11) 协议,理论上所有支持OneBot-v11 [反向WebSocket](https://github.com/botuniverse/onebot-11/blob/master/communication/ws-reverse.md) 的机器人框架都可以连接,不仅限于cqhttp。_
|
||||||
|
|
||||||
_TODO: 计划会出一个极简的纯对话协议,比OneBot更简单,方便第三方对接。_
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group 'com.github.jie65535.openchat'
|
group 'com.github.jie65535.openchat'
|
||||||
version 'dev-0.2.0'
|
version '1.0.0'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import java.util.regex.Pattern;
|
|||||||
public class MiniOneBot implements WsStream.WsMessageHandler {
|
public class MiniOneBot implements WsStream.WsMessageHandler {
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
private final Javalin javalin;
|
private final Javalin javalin;
|
||||||
private final String token;
|
private String token;
|
||||||
private MiniOneBotWsServer server;
|
private MiniOneBotWsServer server;
|
||||||
// private MiniOneBotWsClient client;
|
// private MiniOneBotWsClient client;
|
||||||
|
|
||||||
@@ -43,6 +43,21 @@ public class MiniOneBot implements WsStream.WsMessageHandler {
|
|||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新OneBot Token
|
||||||
|
* @param token 授权令牌
|
||||||
|
*/
|
||||||
|
public void setToken(String token) {
|
||||||
|
if (!Objects.equals(this.token, token)) {
|
||||||
|
this.token = token;
|
||||||
|
if (server != null)
|
||||||
|
server.setToken(token);
|
||||||
|
// if (client != null)
|
||||||
|
// client.setToken(token);
|
||||||
|
logger.info("MiniOneBot Token changed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// region WebSocket
|
// region WebSocket
|
||||||
|
|
||||||
public void startWsServer(String path) {
|
public void startWsServer(String path) {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
|
|
||||||
public class MiniOneBotWsServer implements WsStream, Closeable {
|
public class MiniOneBotWsServer implements WsStream, Closeable {
|
||||||
|
|
||||||
private final String token;
|
private String token;
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
private final Map<WsContext, String> connections = new ConcurrentHashMap<>();
|
private final Map<WsContext, String> connections = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
@@ -46,6 +46,10 @@ public class MiniOneBotWsServer implements WsStream, Closeable {
|
|||||||
logger.info("WebSocket server started at {}", path);
|
logger.info("WebSocket server started at {}", path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setToken(String token) {
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
|
|
||||||
public void onConnect(WsConnectContext ctx) {
|
public void onConnect(WsConnectContext ctx) {
|
||||||
logger.info("onConnect: address={} headers={}", ctx.session.getRemoteAddress(), ctx.headerMap());
|
logger.info("onConnect: address={} headers={}", ctx.session.getRemoteAddress(), ctx.headerMap());
|
||||||
var author = ctx.header("Authorization");
|
var author = ctx.header("Authorization");
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.github.jie65535.openchat;
|
package com.github.jie65535.openchat;
|
||||||
|
|
||||||
|
import emu.grasscutter.command.CommandMap;
|
||||||
|
import emu.grasscutter.server.event.game.ReceiveCommandFeedbackEvent;
|
||||||
import emu.grasscutter.server.event.player.PlayerJoinEvent;
|
import emu.grasscutter.server.event.player.PlayerJoinEvent;
|
||||||
|
|
||||||
public final class EventListeners {
|
public final class EventListeners {
|
||||||
@@ -26,4 +28,31 @@ public final class EventListeners {
|
|||||||
((OpenChatSystem) cs).onPlayerJoin(event);
|
((OpenChatSystem) cs).onPlayerJoin(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static final StringBuilder consoleMessageHandler = new StringBuilder();
|
||||||
|
private static StringBuilder commandResponseHandler;
|
||||||
|
public static String runConsoleCommand(String rawCommand) {
|
||||||
|
synchronized (consoleMessageHandler) {
|
||||||
|
commandResponseHandler = consoleMessageHandler;
|
||||||
|
consoleMessageHandler.setLength(0);
|
||||||
|
// 尝试执行管理员命令
|
||||||
|
CommandMap.getInstance().invoke(null, null, rawCommand);
|
||||||
|
commandResponseHandler = null;
|
||||||
|
return consoleMessageHandler.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 命令执行反馈事件处理
|
||||||
|
*/
|
||||||
|
public static void onCommandResponse(ReceiveCommandFeedbackEvent event) {
|
||||||
|
if (commandResponseHandler == null || event.getPlayer() != null) return;
|
||||||
|
|
||||||
|
if (!consoleMessageHandler.isEmpty()) {
|
||||||
|
// New line
|
||||||
|
consoleMessageHandler.append(System.lineSeparator());
|
||||||
|
}
|
||||||
|
consoleMessageHandler.append(event.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import com.github.jie65535.openchat.utils.SensitiveWordFilter;
|
|||||||
import emu.grasscutter.plugin.Plugin;
|
import emu.grasscutter.plugin.Plugin;
|
||||||
import emu.grasscutter.server.event.EventHandler;
|
import emu.grasscutter.server.event.EventHandler;
|
||||||
import emu.grasscutter.server.event.HandlerPriority;
|
import emu.grasscutter.server.event.HandlerPriority;
|
||||||
|
import emu.grasscutter.server.event.game.ReceiveCommandFeedbackEvent;
|
||||||
import emu.grasscutter.server.event.player.PlayerJoinEvent;
|
import emu.grasscutter.server.event.player.PlayerJoinEvent;
|
||||||
import emu.grasscutter.utils.JsonUtils;
|
import emu.grasscutter.utils.JsonUtils;
|
||||||
|
|
||||||
@@ -37,6 +38,10 @@ public final class OpenChatPlugin extends Plugin {
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private OpenChatSystem openChatSystem;
|
||||||
|
public OpenChatSystem getOpenChatSystem() {
|
||||||
|
return openChatSystem;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoad() {
|
public void onLoad() {
|
||||||
@@ -54,13 +59,18 @@ public final class OpenChatPlugin extends Plugin {
|
|||||||
.priority(HandlerPriority.NORMAL)
|
.priority(HandlerPriority.NORMAL)
|
||||||
.listener(EventListeners::onJoin)
|
.listener(EventListeners::onJoin)
|
||||||
.register(this);
|
.register(this);
|
||||||
|
new EventHandler<>(ReceiveCommandFeedbackEvent.class)
|
||||||
|
.priority(HandlerPriority.NORMAL)
|
||||||
|
.listener(EventListeners::onCommandResponse)
|
||||||
|
.register(this);
|
||||||
|
|
||||||
// Register commands.
|
// Register commands.
|
||||||
getHandle().registerCommand(new ChatServerCommands());
|
getHandle().registerCommand(new ChatServerCommands());
|
||||||
getHandle().registerCommand(new ChatPlayerCommands());
|
getHandle().registerCommand(new ChatPlayerCommands());
|
||||||
|
|
||||||
// Set my chat system.
|
// Set my chat system.
|
||||||
getServer().setChatSystem(new OpenChatSystem(this));
|
openChatSystem = new OpenChatSystem(this);
|
||||||
|
getServer().setChatSystem(openChatSystem);
|
||||||
|
|
||||||
// Log a plugin status message.
|
// Log a plugin status message.
|
||||||
getLogger().info("[OpenChat] Enabled, see https://github.com/jie65535/gc-openchat-plugin");
|
getLogger().info("[OpenChat] Enabled, see https://github.com/jie65535/gc-openchat-plugin");
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ package com.github.jie65535.openchat;
|
|||||||
import com.github.jie65535.minionebot.MiniOneBot;
|
import com.github.jie65535.minionebot.MiniOneBot;
|
||||||
import com.github.jie65535.minionebot.events.GroupMessage;
|
import com.github.jie65535.minionebot.events.GroupMessage;
|
||||||
import emu.grasscutter.GameConstants;
|
import emu.grasscutter.GameConstants;
|
||||||
import emu.grasscutter.command.CommandMap;
|
|
||||||
import emu.grasscutter.game.chat.ChatSystem;
|
import emu.grasscutter.game.chat.ChatSystem;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.server.event.player.PlayerJoinEvent;
|
import emu.grasscutter.server.event.player.PlayerJoinEvent;
|
||||||
@@ -45,6 +44,19 @@ public class OpenChatSystem extends ChatSystem {
|
|||||||
|
|
||||||
// 获取HttpServer框架
|
// 获取HttpServer框架
|
||||||
var javalin = plugin.getHandle().getHttpServer().getHandle();
|
var javalin = plugin.getHandle().getHttpServer().getHandle();
|
||||||
|
// 构造MiniOneBot
|
||||||
|
miniOneBot = new MiniOneBot(javalin, loadToken(), logger);
|
||||||
|
// 启动WebSocket服务
|
||||||
|
miniOneBot.startWsServer(plugin.getConfig().wsPath);
|
||||||
|
// 订阅群消息事件
|
||||||
|
miniOneBot.subscribeGroupMessageEvent(this::onGroupMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从配置文件中载入WsToken,如果为空则生成一个
|
||||||
|
* @return Token
|
||||||
|
*/
|
||||||
|
private String loadToken() {
|
||||||
var token = plugin.getConfig().wsToken;
|
var token = plugin.getConfig().wsToken;
|
||||||
if (token == null || token.isEmpty()) {
|
if (token == null || token.isEmpty()) {
|
||||||
token = Utils.base64Encode(Crypto.createSessionKey(24));
|
token = Utils.base64Encode(Crypto.createSessionKey(24));
|
||||||
@@ -52,12 +64,14 @@ public class OpenChatSystem extends ChatSystem {
|
|||||||
plugin.saveConfig();
|
plugin.saveConfig();
|
||||||
logger.warn("Detected that wsToken is empty, automatically generated Token for you as follows: {}", token);
|
logger.warn("Detected that wsToken is empty, automatically generated Token for you as follows: {}", token);
|
||||||
}
|
}
|
||||||
// 构造MiniOneBot
|
return token;
|
||||||
miniOneBot = new MiniOneBot(javalin, token, logger);
|
}
|
||||||
// 启动WebSocket服务
|
|
||||||
miniOneBot.startWsServer(plugin.getConfig().wsPath);
|
/**
|
||||||
// 订阅群消息事件
|
* 重新载入Token
|
||||||
miniOneBot.subscribeGroupMessageEvent(this::onGroupMessage);
|
*/
|
||||||
|
public void reloadToken() {
|
||||||
|
miniOneBot.setToken(loadToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -244,9 +258,9 @@ public class OpenChatSystem extends ChatSystem {
|
|||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
logger.info("Command used by op [{}({})]: {}", event.senderCardOrNickname(), event.senderId(), event.message());
|
logger.info("Command used by op [{}({})]: {}", event.senderCardOrNickname(), event.senderId(), event.message());
|
||||||
// 尝试执行管理员命令
|
String rawCommand = event.message().substring(plugin.getConfig().adminPrefix.length());
|
||||||
CommandMap.getInstance().invoke(null, null,
|
String result = EventListeners.runConsoleCommand(rawCommand);
|
||||||
event.message().substring(plugin.getConfig().adminPrefix.length()));
|
miniOneBot.sendGroupMessage(event.groupId(), result);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.error("Administrator command execution failed", ex);
|
logger.error("Administrator command execution failed", ex);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,8 +106,12 @@ public class ChatServerCommands implements CommandHandler {
|
|||||||
CommandHandler.sendMessage(sender, "OK");
|
CommandHandler.sendMessage(sender, "OK");
|
||||||
}
|
}
|
||||||
case "reload" -> {
|
case "reload" -> {
|
||||||
|
// 重载配置
|
||||||
plugin.loadConfig();
|
plugin.loadConfig();
|
||||||
|
// 重载敏感词
|
||||||
plugin.loadSensitiveWordList();
|
plugin.loadSensitiveWordList();
|
||||||
|
// 重载令牌
|
||||||
|
plugin.getOpenChatSystem().reloadToken();
|
||||||
CommandHandler.sendMessage(sender, "OK");
|
CommandHandler.sendMessage(sender, "OK");
|
||||||
}
|
}
|
||||||
case "group" -> {
|
case "group" -> {
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "openchat-plugin",
|
"name": "openchat-plugin",
|
||||||
"description": "Chat with players in the server console",
|
"description": "Chat with players in the server console",
|
||||||
"version": "0.1.0",
|
"version": "1.0.0",
|
||||||
"mainClass": "com.github.jie65535.openchat.OpenChatPlugin",
|
"mainClass": "com.github.jie65535.openchat.OpenChatPlugin",
|
||||||
"authors": ["jie65535"]
|
"authors": ["jie65535"],
|
||||||
|
"api": 2
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user