Compare commits

...

6 Commits

Author SHA1 Message Date
d64238a9e9 Fix CI branch 2023-05-21 21:13:59 +08:00
c3667a8206 Add unstable description 2023-05-21 21:10:52 +08:00
c62d777037 Add url to enable log
(cherry picked from commit 66fb25aa9b)
2023-05-21 21:04:41 +08:00
5019b6548a Update player command response handler 2023-05-21 20:50:34 +08:00
1c8d448a7b Update baseName to opencommand-for-unstable 2023-05-21 20:38:22 +08:00
99f914b952 Update CI gc path 2023-05-21 20:01:11 +08:00
8 changed files with 77 additions and 32 deletions

View File

@ -5,7 +5,7 @@ on:
paths:
- "**.java"
branches:
- "main"
- "for-unstable"
pull_request:
paths:
- "**.java"
@ -35,7 +35,7 @@ jobs:
restore-keys: |
${{ runner.os }}-gradle-
- name: Download latest grasscutter jar
run: wget https://nightly.link/Grasscutters/Grasscutter/workflows/build/development/Grasscutter.zip && mkdir lib && unzip Grasscutter.zip -d lib
run: wget https://nightly.link/Grasscutters/Grasscutter/workflows/build/unstable/Grasscutter.zip && mkdir lib && unzip Grasscutter.zip -d lib
- name: Change permission
run: chmod +x gradlew

View File

@ -4,6 +4,10 @@
一个为第三方客户端开放GC命令执行接口的插件
## 分支说明
本分支目的在于兼容 GC 的 `unstable` 分支
## 使用本插件的应用
- [GrasscutterTools](https://github.com/jie65535/GrasscutterCommandGenerator) —— Windows 客户端工具
- [JGrasscutterCommand](https://github.com/jie65535/JGrasscutterCommand) —— [Mirai](https://github.com/mamoe/mirai) 插件在QQ里执行命令
@ -70,7 +74,7 @@
## `config.json`
```json
```json5
{
// 控制台连接令牌
"consoleToken": "",
@ -259,7 +263,7 @@ public final class JsonResponse {
| message | `Success` | `String` |
| data | `{}` | `JsonObject` |
```json
```json5
{
"retcode": 200,
"message": "success",

View File

@ -4,6 +4,10 @@
A plugin that opens the GC command execution interface for third-party clients
## Branch Description
The purpose of this branch is to be compatible with the 'unstable' branch of GC
## Applications using this plug-in
- [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
@ -244,7 +248,7 @@ Success
| message | `Success` | `String` |
| data | `{}` | `JsonObject` |
```json
```json5
{
"retcode": 200,
"message": "success",

View File

@ -18,7 +18,7 @@ dependencies {
}
jar {
jar.baseName = 'opencommand'
jar.baseName = 'opencommand-for-unstable'
destinationDir = file(".")
}

View File

@ -24,24 +24,54 @@ import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.event.game.ReceiveCommandFeedbackEvent;
import emu.grasscutter.server.event.player.PlayerJoinEvent;
import emu.grasscutter.server.event.player.PlayerQuitEvent;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.util.ArrayList;
public final class EventListeners {
private static StringBuilder consoleMessageHandler;
private static final Int2ObjectMap<StringBuilder> playerMessageHandlers = new Int2ObjectOpenHashMap<>();
public static void setConsoleMessageHandler(StringBuilder handler) {
consoleMessageHandler = handler;
}
/**
* 获取新的玩家消息处理类
* 获取时将创建或清空消息处理器并返回实例**在执行命令前获取**
* @param uid 玩家uid
* @return 新的玩家消息处理类
*/
public static StringBuilder getPlayerNewMessageHandler(int uid) {
var handler = playerMessageHandlers.get(uid);
if (handler == null) {
handler = new StringBuilder();
playerMessageHandlers.put(uid, handler);
} else {
handler.setLength(0);
}
return handler;
}
/**
* 命令执行反馈事件处理
*/
public static void onCommandResponse(ReceiveCommandFeedbackEvent event) {
if (consoleMessageHandler != null && event.getPlayer() == null) {
if (!consoleMessageHandler.isEmpty()) {
StringBuilder handler;
if (event.getPlayer() == null) {
handler = consoleMessageHandler;
} else {
handler = playerMessageHandlers.get(event.getPlayer().getUid());
}
if (handler != null) {
if (!handler.isEmpty()) {
// New line
consoleMessageHandler.append(System.lineSeparator());
handler.append(System.lineSeparator());
}
consoleMessageHandler.append(event.getMessage());
handler.append(event.getMessage());
}
}
@ -60,6 +90,10 @@ public final class EventListeners {
SocketClient.sendPacket(playerList);
}
/**
* 仅游戏模式下玩家离开事件处理方法
* 用于更新玩家列表
*/
public static void onPlayerQuit(PlayerQuitEvent playerQuitEvent) {
PlayerList playerList = new PlayerList();
playerList.player = Grasscutter.getGameServer().getPlayers().size();
@ -73,4 +107,15 @@ public final class EventListeners {
playerList.playerList = playerNames;
SocketClient.sendPacket(playerList);
}
/**
* 玩家离开事件处理 2
* 用于清理内存
*/
public static void onPlayerQuit2(PlayerQuitEvent playerQuitEvent) {
var uid = playerQuitEvent.getPlayer().getUid();
if (playerMessageHandlers.containsKey(uid)) {
playerMessageHandlers.remove(uid);
}
}
}

View File

@ -24,7 +24,6 @@ import com.github.jie65535.opencommand.socket.SocketData;
import emu.grasscutter.command.CommandMap;
import emu.grasscutter.server.http.Router;
import emu.grasscutter.utils.Crypto;
import emu.grasscutter.utils.MessageHandler;
import emu.grasscutter.utils.Utils;
import io.javalin.Javalin;
import io.javalin.http.Context;
@ -46,7 +45,6 @@ public final class OpenCommandHandler implements Router {
private static final Map<String, Integer> codes = new HashMap<>();
private static final Int2ObjectMap<Date> codeExpireTime = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<MessageHandler> playerMessageHandlers = new Int2ObjectOpenHashMap<>();
public static void handle(Context context) {
var plugin = OpenCommandPlugin.getInstance();
@ -154,24 +152,16 @@ public final class OpenCommandHandler implements Router {
context.json(new JsonResponse(404, "Player not found"));
return;
}
// Player MessageHandler do not support concurrency
var handler = playerMessageHandlers.get(player.getUid());
if (handler == null) {
handler = new MessageHandler();
playerMessageHandlers.put(player.getUid(), handler);
}
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (handler) {
synchronized (player) {
// Player MessageHandler do not support concurrency
var handler = EventListeners.getPlayerNewMessageHandler(player.getUid());
try {
handler.setMessage("");
player.setMessageHandler(handler);
CommandMap.getInstance().invoke(player, player, command);
context.json(new JsonResponse(handler.getMessage()));
context.json(new JsonResponse(handler.toString()));
} catch (Exception e) {
plugin.getLogger().warn("Run command failed.", e);
context.json(new JsonResponse(500, "error", e.getLocalizedMessage()));
} finally {
player.setMessageHandler(null);
}
}
return;

View File

@ -59,10 +59,16 @@ public final class OpenCommandPlugin extends Plugin {
@Override
public void onEnable() {
// 监听命令执行反馈
new EventHandler<>(ReceiveCommandFeedbackEvent.class)
.priority(HandlerPriority.HIGH)
.listener(EventListeners::onCommandResponse)
.register(this);
// 监听玩家离开事件
new EventHandler<>(PlayerQuitEvent.class)
.priority(HandlerPriority.NORMAL)
.listener(EventListeners::onPlayerQuit2)
.register(this);
if (runMode == Grasscutter.ServerRunMode.GAME_ONLY) {
// 仅运行游戏服务器时注册玩家加入和离开事件
new EventHandler<>(PlayerJoinEvent.class)
@ -78,7 +84,7 @@ public final class OpenCommandPlugin extends Plugin {
} else {
getHandle().addRouter(OpenCommandHandler.class);
}
getLogger().info("[OpenCommand] Enabled");
getLogger().info("[OpenCommand] Enabled. https://github.com/jie65535/gc-opencommand-plugin");
}
@Override

View File

@ -26,7 +26,6 @@ import com.github.jie65535.opencommand.socket.packet.player.PlayerList;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.CommandMap;
import emu.grasscutter.utils.JsonUtils;
import emu.grasscutter.utils.MessageHandler;
import org.slf4j.Logger;
import java.io.IOException;
@ -160,19 +159,16 @@ public class SocketClient {
sendPacket(new HttpPacket(404, "Player not found."), packet.packetID);
return;
}
// Player MessageHandler do not support concurrency
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (playerData) {
// Player MessageHandler do not support concurrency
var handler = EventListeners.getPlayerNewMessageHandler(playerData.getUid());
try {
var resultCollector = new MessageHandler();
playerData.setMessageHandler(resultCollector);
CommandMap.getInstance().invoke(playerData, playerData, command);
sendPacket(new HttpPacket(200, resultCollector.getMessage()), packet.packetID);
sendPacket(new HttpPacket(200, handler.toString()), packet.packetID);
} catch (Exception e) {
OpenCommandPlugin.getInstance().getLogger().warn("[OpenCommand] Run command failed.", e);
sendPacket(new HttpPacket(500, "error", e.getLocalizedMessage()), packet.packetID);
} finally {
playerData.setMessageHandler(null);
}
}
}