Support multi-line commands

Update auto-generate console token
This commit is contained in:
2023-09-02 18:38:59 +08:00
parent e9e2805738
commit 1b86226951
4 changed files with 111 additions and 76 deletions

View File

@ -4,6 +4,14 @@
一个为第三方客户端开放GC命令执行接口的插件 一个为第三方客户端开放GC命令执行接口的插件
`1.7.0` 起可以通过 `|` 或者换行来分隔多条命令,例如:
```shell
/a 1 | /a 2
/a 3
```
调用 `ping` 响应数据将包含插件版本号。
## 使用本插件的应用 ## 使用本插件的应用
- [GrasscutterTools](https://github.com/jie65535/GrasscutterCommandGenerator) —— Windows 客户端工具 - [GrasscutterTools](https://github.com/jie65535/GrasscutterCommandGenerator) —— Windows 客户端工具
- [JGrasscutterCommand](https://github.com/jie65535/JGrasscutterCommand) —— [Mirai](https://github.com/mamoe/mirai) 插件在QQ里执行命令 - [JGrasscutterCommand](https://github.com/jie65535/JGrasscutterCommand) —— [Mirai](https://github.com/mamoe/mirai) 插件在QQ里执行命令
@ -15,43 +23,13 @@
1. 在 [Release](https://github.com/jie65535/gc-opencommand-plugin/releases) 下载 `jar` 1. 在 [Release](https://github.com/jie65535/gc-opencommand-plugin/releases) 下载 `jar`
2. 放入 `plugins` 文件夹即可 2. 放入 `plugins` 文件夹即可
> 注意,如果出现以下错误:
> ```log
> INFO:PluginManager Enabling plugin: opencommand-plugin
> Exception in thread "main" java.lang.NoSuchMethodError: 'void emu.grasscutter.server.event.EventHandler.register(emu.grasscutter.plugin.Plugin)'
> at com.github.jie65535.opencommand.OpenCommandPlugin.onEnable(OpenCommandPlugin.java:49)
> at emu.grasscutter.plugin.PluginManager.lambda$enablePlugins$3(PluginManager.java:131)
> ```
> 请使用v1.2.1版本插件,因为该报错表示你的服务端是旧版!
## 控制台连接 ## 控制台连接
1. 首次启动时,会在 `plugins` 目录下生成一个 `opencommand-plugin` 目录,打开并编辑 `config.json` 1. 首次启动时,会在 `plugins` 目录下生成一个 `opencommand-plugin` 目录,打开并编辑 `config.json`
2. 设置 `consoleToken` 的值为你的连接秘钥建议使用至少32字符的长随机字符串。 2. 设置 `consoleToken` 的值为你的连接秘钥建议使用至少32字符的长随机字符串。检测到为空时会自动生成
3. 重新启动服务端即可生效配置 3. 重新启动服务端即可生效配置
4. 在客户端中选择控制台身份,并填写你的 `consoleToken` 即可以控制台身份运行指令 4. 在客户端中选择控制台身份,并填写你的 `consoleToken` 即可以控制台身份运行指令
## 多服务器
### 主服务器 (Dispatch)
1. 在 `opencommand-plugin` 目录下打开 `config.json`
2. 修改 `socketPort` 值为一个未被使用的端口
3. 设置 `socketToken` 多服务器通信密钥建议使用至少32字符的长随机字符串。
4. 重新启动服务端即可生效配置
### 子服务器 (Game)
1. 在 `opencommand-plugin` 目录下打开 `config.json`
2. 修改 `socketHost``socketPort` 值为主服务器的地址和端口
3. 设置 `socketToken` 和主服务器相同的值
4. 设置 `socketDisplayName` 值为你的服务器名称 (用途请见[下方](https://github.com/jie65535/gc-opencommand-plugin#%E8%8E%B7%E5%8F%96%E5%A4%9A%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%88%97%E8%A1%A8))
5. 重新启动服务端即可生效配置
## 构建说明
1. 克隆仓库
2. 在目录下新建 `lib` 目录
3. 将 `grasscutter-1.1.x-dev.jar` 放入 `lib` 目录
4. `gradle build`
## 玩家使用流程 ## 玩家使用流程
1. 在客户端中填写服务地址,确认是否支持 1. 在客户端中填写服务地址,确认是否支持
@ -66,13 +44,34 @@
3. 使用 `token` 和**4位整数验证码**发送 `verify` 校验 3. 使用 `token` 和**4位整数验证码**发送 `verify` 校验
4. 如果验证通过,可以使用该 `token` 执行 `command` 动作 4. 如果验证通过,可以使用该 `token` 执行 `command` 动作
## 插件构建说明
1. 克隆仓库
2. 在目录下新建 `lib` 目录
3. 将 `grasscutter-1.1.x-dev.jar` 放入 `lib` 目录
4. `gradle build`
## 多服务器
### 主服务器 (Dispatch)
1. 在 `opencommand-plugin` 目录下打开 `config.json`
2. 修改 `socketPort` 值为一个未被使用的端口
3. 设置 `socketToken` 多服务器通信密钥建议使用至少32字符的长随机字符串。
4. 重新启动服务端即可生效配置
### 子服务器 (Game)
1. 在 `opencommand-plugin` 目录下打开 `config.json`
2. 修改 `socketHost``socketPort` 值为主服务器的地址和端口
3. 设置 `socketToken` 和主服务器相同的值
4. 设置 `socketDisplayName` 值为你的服务器名称 (用途请见[下方](https://github.com/jie65535/gc-opencommand-plugin#%E8%8E%B7%E5%8F%96%E5%A4%9A%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%88%97%E8%A1%A8))
5. 重新启动服务端即可生效配置
--- ---
## `config.json` ## `config.json`
```json ```json5
{ {
// 控制台连接令牌 // 控制台连接令牌(检测到空时会自动生成)
"consoleToken": "", "consoleToken": "",
// 验证码过期时间(秒) // 验证码过期时间(秒)
"codeExpirationTime_S": 60, "codeExpirationTime_S": 60,
@ -259,7 +258,7 @@ public final class JsonResponse {
| message | `Success` | `String` | | message | `Success` | `String` |
| data | `{}` | `JsonObject` | | data | `{}` | `JsonObject` |
```json ```json5
{ {
"retcode": 200, "retcode": 200,
"message": "success", "message": "success",

View File

@ -4,10 +4,19 @@
A plugin that opens the GC command execution interface for third-party clients A plugin that opens the GC command execution interface for third-party clients
Since `1.7.0`, multiple commands can be separated by `|` or newline, for example:
```shell
/a 1 | /a 2
/a 3
```
Invoking `ping` the response data will contain the plugin version.
## Applications using this plug-in ## Applications using this plug-in
- [GrasscutterTools](https://github.com/jie65535/GrasscutterCommandGenerator) —— Windows Client Tools - [GrasscutterTools](https://github.com/jie65535/GrasscutterCommandGenerator) —— Windows Client Tools
- [JGrasscutterCommand](https://github.com/jie65535/JGrasscutterCommand) —— [Mirai](https://github.com/mamoe/mirai) Plugin, run commands in QQ - [JGrasscutterCommand](https://github.com/jie65535/JGrasscutterCommand) —— [Mirai](https://github.com/mamoe/mirai) Plugin, run commands in QQ
- TODO - [Yunzai-GrasscutterCommand](https://github.com/Zyy-boop/Yunzai-GrasscutterCommand) —— Yunzai-bot plugin, execute commands in QQ
- More...
## Server installation ## Server installation
@ -19,32 +28,10 @@ A plugin that opens the GC command execution interface for third-party clients
1. When starting for the first time, a `opencommand-plugin` directory will be generated under the `plugins` directory, 1. When starting for the first time, a `opencommand-plugin` directory will be generated under the `plugins` directory,
open and edit `config.json` open and edit `config.json`
2. Set the value of `consoleToken` to your connection key. It is recommended to use a long random string of at least 32 2. Set the value of `consoleToken` to your connection key. It is recommended to use a long random string of at least 32
characters. characters. (automatically generated when empty is detected)
3. Restart the server to take effect 3. Restart the server to take effect
4. Select the console identity in the client, and fill in your `consoleToken` to run the command as the console identity 4. Select the console identity in the client, and fill in your `consoleToken` to run the command as the console identity
## Multi server
### Master server (Dispatch)
1. Open `config.json` in the `opencommand-plugin` directory
2. Modify the `socketPort` value to an unused port
3. Set `sockettoken` multi server communication key. It is recommended to use a long random string of at least 32 characters.
4. Restart the server to make the configuration effective
### Sub server (Game)
1. Open `config.json` in the `opencommand-plugin` directory
2. Modify the `sockethost` and `socketport` values to the address and port of the primary server
3. Set the same value of `sockettoken` and the primary server
4. Set the `socketDisplayName` value to your server name (See below for usage [Jump](https://github.com/jie65535/gc-opencommand-plugin/blob/master/README_en-US.md#get-mulit-server-list))
5. Restart the server to make the configuration effective
## Build
1. `git clone https://github.com/jie65535/gc-opencommand-plugin`
2. `cd gc-opencommand-plugin`
3. `mkdir lib`
4. `mv path/to/grasscutter-1.x.x-dev.jar ./lib`
5. `gradle build`
## Player ## Player
1. Fill in the service address in the client to confirm whether it supports 1. Fill in the service address in the client to confirm whether it supports
@ -60,19 +47,50 @@ A plugin that opens the GC command execution interface for third-party clients
3. Send `verify` check using `token` and **4-digit integer verification code** 3. Send `verify` check using `token` and **4-digit integer verification code**
4. If the verification is passed, you can use the `token` to execute the `command` action 4. If the verification is passed, you can use the `token` to execute the `command` action
## Build
1. `git clone https://github.com/jie65535/gc-opencommand-plugin`
2. `cd gc-opencommand-plugin`
3. `mkdir lib`
4. `mv path/to/grasscutter-1.x.x-dev.jar ./lib`
5. `gradle build`
## Multi server
### Master server (Dispatch)
1. Open `config.json` in the `opencommand-plugin` directory
2. Modify the `socketPort` value to an unused port
3. Set `sockettoken` multi server communication key. It is recommended to use a long random string of at least 32 characters.
4. Restart the server to make the configuration effective
### Sub server (Game)
1. Open `config.json` in the `opencommand-plugin` directory
2. Modify the `sockethost` and `socketport` values to the address and port of the primary server
3. Set the same value of `sockettoken` and the primary server
4. Set the `socketDisplayName` value to your server name (See below for usage [Jump](https://github.com/jie65535/gc-opencommand-plugin/blob/master/README_en-US.md#get-mulit-server-list))
5. Restart the server to make the configuration effective
--- ---
## `config.json` ## `config.json`
```json ```json5
{ {
// console connection token (automatically generated when empty is detected)
"consoleToken": "", "consoleToken": "",
// Verification code expiration time (seconds)
"codeExpirationTime_S": 60, "codeExpirationTime_S": 60,
// Temporary token expiration time (seconds)
"tempTokenExpirationTime_S": 300, "tempTokenExpirationTime_S": 300,
// Authorization token last used expiration time (hours)
"tokenLastUseExpirationTime_H": 48, "tokenLastUseExpirationTime_H": 48,
// Multi-server communication port
"socketPort": 5746, "socketPort": 5746,
// Multi-server communication key
"socketToken": "", "socketToken": "",
"socketHost": "127.0.0.1" // Multi-server Dispatch server address
"socketHost": "127.0.0.1",
// multi-server display name
"socketDisplayName": ""
} }
``` ```
@ -244,7 +262,7 @@ Success
| message | `Success` | `String` | | message | `Success` | `String` |
| data | `{}` | `JsonObject` | | data | `{}` | `JsonObject` |
```json ```json5
{ {
"retcode": 200, "retcode": 200,
"message": "success", "message": "success",

View File

@ -83,7 +83,7 @@ public final class OpenCommandHandler implements Router {
} }
return; return;
} else if (req.action.equals("ping")) { } else if (req.action.equals("ping")) {
context.json(new JsonResponse()); context.json(new JsonResponse(plugin.getVersion()));
return; return;
} else if (req.action.equals("online")) { } else if (req.action.equals("online")) {
var p = new ArrayList<String>(); var p = new ArrayList<String>();
@ -147,7 +147,7 @@ public final class OpenCommandHandler implements Router {
// update token expire time // update token expire time
client.tokenExpireTime = new Date(now.getTime() + config.tokenLastUseExpirationTime_H * 60L * 60L * 1000L); client.tokenExpireTime = new Date(now.getTime() + config.tokenLastUseExpirationTime_H * 60L * 60L * 1000L);
var player = plugin.getServer().getPlayerByUid(client.playerId); var player = plugin.getServer().getPlayerByUid(client.playerId);
var command = req.data.toString(); var rawMessage = req.data.toString();
if (player == null) { if (player == null) {
context.json(new JsonResponse(404, "Player not found")); context.json(new JsonResponse(404, "Player not found"));
return; return;
@ -158,7 +158,12 @@ public final class OpenCommandHandler implements Router {
synchronized (handler) { synchronized (handler) {
try { try {
handler.setLength(0); handler.setLength(0);
for (var command : rawMessage.split("\n[/!]|\\|")) {
if (command.charAt(0) == '/' || command.charAt(0) == '!') {
command = command.substring(1);
}
CommandMap.getInstance().invoke(player, player, command); CommandMap.getInstance().invoke(player, player, command);
}
context.json(new JsonResponse(handler.toString())); context.json(new JsonResponse(handler.toString()));
} catch (Exception e) { } catch (Exception e) {
plugin.getLogger().warn("Run command failed.", e); plugin.getLogger().warn("Run command failed.", e);

View File

@ -26,7 +26,9 @@ import emu.grasscutter.server.event.HandlerPriority;
import emu.grasscutter.server.event.game.ReceiveCommandFeedbackEvent; import emu.grasscutter.server.event.game.ReceiveCommandFeedbackEvent;
import emu.grasscutter.server.event.player.PlayerJoinEvent; import emu.grasscutter.server.event.player.PlayerJoinEvent;
import emu.grasscutter.server.event.player.PlayerQuitEvent; import emu.grasscutter.server.event.player.PlayerQuitEvent;
import emu.grasscutter.utils.Crypto;
import emu.grasscutter.utils.JsonUtils; import emu.grasscutter.utils.JsonUtils;
import emu.grasscutter.utils.Utils;
import java.io.*; import java.io.*;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -105,6 +107,33 @@ public final class OpenCommandPlugin extends Plugin {
var configFile = new File(getDataFolder(), "config.json"); var configFile = new File(getDataFolder(), "config.json");
if (!configFile.exists()) { if (!configFile.exists()) {
config = new OpenCommandConfig(); config = new OpenCommandConfig();
saveConfig();
} else {
try {
config = JsonUtils.decode(Files.readString(configFile.toPath(), StandardCharsets.UTF_8),
OpenCommandConfig.class);
} catch (Exception exception) {
config = new OpenCommandConfig();
getLogger().error("[OpenCommand] There was an error while trying to load the configuration from config.json. Please make sure that there are no syntax errors. If you want to start with a default configuration, delete your existing config.json.");
}
}
// 检查控制台Token
if (config.consoleToken == null || config.consoleToken.isEmpty()) {
config.consoleToken = Utils.base64Encode(Crypto.createSessionKey(24));
saveConfig();
getLogger().warn("Detected that consoleToken is empty, automatically generated Token for you as follows: {}", config.consoleToken);
}
try {
runMode = Grasscutter.getConfig().server.runMode;
} catch (Exception ex) {
getLogger().warn("[OpenCommand] Failed to load server configuration, default HYBRID mode is being used.");
}
}
private void saveConfig() {
var configFile = new File(getDataFolder(), "config.json");
try (var file = new FileWriter(configFile)) { try (var file = new FileWriter(configFile)) {
file.write(JsonUtils.encode(config)); file.write(JsonUtils.encode(config));
} catch (IOException e) { } catch (IOException e) {
@ -112,22 +141,6 @@ public final class OpenCommandPlugin extends Plugin {
} catch (Exception e) { } catch (Exception e) {
getLogger().error("[OpenCommand] Unable to save config file."); getLogger().error("[OpenCommand] Unable to save config file.");
} }
} else {
try {
config = JsonUtils.decode(Files.readString(configFile.toPath(), StandardCharsets.UTF_8),
OpenCommandConfig.class);
} catch (Exception exception) {
getLogger().error("[OpenCommand] There was an error while trying to load the configuration from config.json. Please make sure that there are no syntax errors. If you want to start with a default configuration, delete your existing config.json.");
}
if (config == null) {
config = new OpenCommandConfig();
}
}
try {
runMode = Grasscutter.getConfig().server.runMode;
} catch (Exception ex) {
getLogger().warn("[OpenCommand] Failed to load server configuration, default HYBRID mode is being used.");
}
} }
private void loadData() { private void loadData() {