diff --git a/.idea/fileTemplates/includes/Version.txt b/.idea/fileTemplates/includes/Version.txt
index afaf360..e6d5cb8 100644
--- a/.idea/fileTemplates/includes/Version.txt
+++ b/.idea/fileTemplates/includes/Version.txt
@@ -1 +1 @@
-1.0.0
\ No newline at end of file
+1.0.2
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..e5cd645
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index 8048d28..601fce8 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -4,7 +4,7 @@ import com.github.jengelman.gradle.plugins.shadow.transformers.Log4j2PluginsCach
val projectName = rootProject.name
val groupName by extra("cn.wzpmc")
val projectArtifactId by extra("my-bot")
-val projectVersion by extra("1.0.0")
+val projectVersion by extra("1.0.1")
plugins {
id("java")
diff --git a/src/main/java/cn/wzpmc/Main.java b/src/main/java/cn/wzpmc/Main.java
index 9c66221..d89c481 100644
--- a/src/main/java/cn/wzpmc/Main.java
+++ b/src/main/java/cn/wzpmc/Main.java
@@ -3,7 +3,11 @@ package cn.wzpmc;
import cn.wzpmc.api.api.IMainApi;
import cn.wzpmc.api.api.actions.message.get.GetLoginInfoAction;
import cn.wzpmc.api.plugins.BasePlugin;
-import cn.wzpmc.commands.StopCommand;
+import cn.wzpmc.builtin.commands.DeOpCommand;
+import cn.wzpmc.builtin.commands.HelpCommand;
+import cn.wzpmc.builtin.commands.OpCommand;
+import cn.wzpmc.builtin.commands.StopCommand;
+import cn.wzpmc.builtin.event.CommandEventHandler;
import cn.wzpmc.configuration.Configuration;
import cn.wzpmc.console.MyBotConsole;
import cn.wzpmc.entities.user.bot.MyBot;
@@ -87,8 +91,12 @@ public class Main {
}
load.onLoad();
}
+ // 注册内置指令
CommandManager commandManager = myBot.getCommandManager();
commandManager.registerCommand(new StopCommand(myBot));
+ commandManager.registerCommand(new OpCommand());
+ commandManager.registerCommand(new HelpCommand());
+ commandManager.registerCommand(new DeOpCommand());
}
public static WebSocketConnectionHandler createConnection(MyBot myBot, URI uri){
WebSocketConnectionHandler webSocketConnectionHandler = new WebSocketConnectionHandler(myBot);
@@ -120,6 +128,7 @@ public class Main {
IMainApi mainApi = myBot.getMainApi();
// 获取Bot消息
mainApi.doApiCall(new GetLoginInfoAction());
+ myBot.registerEventHandler(new CommandEventHandler());
startConsole(myBot, webSocketConnectionHandler);
}
}
\ No newline at end of file
diff --git a/src/main/java/cn/wzpmc/api/commands/arguments/MessagePartArgument.java b/src/main/java/cn/wzpmc/api/commands/arguments/MessagePartArgument.java
new file mode 100644
index 0000000..4016ad7
--- /dev/null
+++ b/src/main/java/cn/wzpmc/api/commands/arguments/MessagePartArgument.java
@@ -0,0 +1,26 @@
+package cn.wzpmc.api.commands.arguments;
+
+import cn.wzpmc.api.message.json.JsonMessagePart;
+import cn.wzpmc.api.utils.CqCodeUtils;
+import com.mojang.brigadier.LiteralMessage;
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.arguments.ArgumentType;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+
+/**
+ * 消息段参数类型
+ * @author wzp
+ * @version 1.0.0
+ * @since 2024/8/25 01:18
+ */
+public class MessagePartArgument implements ArgumentType {
+ @Override
+ public JsonMessagePart parse(StringReader stringReader) throws CommandSyntaxException {
+ String s = stringReader.readStringUntil(' ');
+ if (!CqCodeUtils.isCQ(s)){
+ throw new CommandSyntaxException(new SimpleCommandExceptionType(new LiteralMessage("MessagePart")), new LiteralMessage("Cannot read message part"));
+ }
+ return CqCodeUtils.parseToPart(s);
+ }
+}
diff --git a/src/main/java/cn/wzpmc/api/commands/arguments/UserIdArguments.java b/src/main/java/cn/wzpmc/api/commands/arguments/UserIdArguments.java
new file mode 100644
index 0000000..5759c3e
--- /dev/null
+++ b/src/main/java/cn/wzpmc/api/commands/arguments/UserIdArguments.java
@@ -0,0 +1,50 @@
+package cn.wzpmc.api.commands.arguments;
+
+import cn.wzpmc.api.message.json.JsonMessagePart;
+import cn.wzpmc.api.message.json.parts.At;
+import cn.wzpmc.api.utils.CqCodeUtils;
+import cn.wzpmc.console.commands.exceptions.CqCodeException;
+import com.mojang.brigadier.LiteralMessage;
+import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.arguments.ArgumentType;
+import com.mojang.brigadier.exceptions.BuiltInExceptions;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+
+/**
+ * 用户ID消息类型
+ * @author wzp
+ * @version 1.0.0
+ * @since 2024/8/25 21:02
+ */
+public class UserIdArguments implements ArgumentType {
+ @Override
+ public Long parse(StringReader stringReader) throws CommandSyntaxException {
+ StringBuilder builder = new StringBuilder();
+ char read = stringReader.read();
+ if (read == '[') {
+ builder.append('[');
+ while (stringReader.canRead()) {
+ read = stringReader.read();
+ builder.append(read);
+ if (read == ']') {
+ break;
+ }
+ }
+ String s = builder.toString();
+ if (CqCodeUtils.isCQ(s)) {
+ JsonMessagePart jsonMessagePart = CqCodeUtils.parseToPart(s);
+ if (jsonMessagePart instanceof At){
+ return ((At) jsonMessagePart).getQq();
+ }
+ throw new CqCodeException();
+ }
+ } else {
+ String s = stringReader.readUnquotedString();
+ String s1 = read + s;
+ try {
+ return Long.parseLong(s1);
+ }catch (NumberFormatException ignored) {}
+ }
+ throw new CommandSyntaxException(new BuiltInExceptions().readerInvalidLong(), new LiteralMessage("Cannot read long from user id"));
+ }
+}
diff --git a/src/main/java/cn/wzpmc/api/entities/Ops.java b/src/main/java/cn/wzpmc/api/entities/Ops.java
new file mode 100644
index 0000000..79adf2c
--- /dev/null
+++ b/src/main/java/cn/wzpmc/api/entities/Ops.java
@@ -0,0 +1,55 @@
+package cn.wzpmc.api.entities;
+
+import lombok.Getter;
+
+import java.util.*;
+
+/**
+ * 分群op列表
+ * @author wzp
+ * @version 1.0.0
+ * @since 2024/8/25 20:16
+ */
+@Getter
+public final class Ops {
+ /**
+ * BOT总管理员
+ * @since 2024/8/25 20:17 v1.0.0
+ */
+ private final Set admins = new HashSet<>();
+ /**
+ * 群内管理员
+ * @since 2024/8/25 20:17 v1.0.0
+ */
+ private final Map> groupAdmins = new HashMap<>();
+
+ /**
+ * 判断此用户在群中是否为管理
+ * @author wzp
+ * @since 2024/8/25 20:20 v1.0.0
+ * @param groupId 群ID
+ * @param id 用户ID
+ * @return 是否管理
+ */
+ public boolean isAdmin(Long groupId, Long id){
+ if (admins.contains(id)){
+ return true;
+ }
+ List longs = groupAdmins.get(groupId.toString());
+ if (longs == null){
+ return false;
+ }
+ return longs.contains(id);
+ }
+
+ /**
+ * 判断此用户是否为管理
+ * @author wzp
+ * @since 2024/8/25 20:20 v1.0.0
+ * @param id 用户ID
+ * @return 是否管理
+ */
+ public boolean isAdmin(Long id) {
+ return admins.contains(id);
+ }
+}
diff --git a/src/main/java/cn/wzpmc/api/message/json/parts/MarkdownMessage.java b/src/main/java/cn/wzpmc/api/message/json/parts/MarkdownMessage.java
new file mode 100644
index 0000000..17f1d86
--- /dev/null
+++ b/src/main/java/cn/wzpmc/api/message/json/parts/MarkdownMessage.java
@@ -0,0 +1,31 @@
+package cn.wzpmc.api.message.json.parts;
+
+import cn.wzpmc.api.message.json.JsonMessagePart;
+import com.alibaba.fastjson2.JSONObject;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+/**
+ * Markdown格式消息
+ * @author wzp
+ * @version 1.0.0
+ * @since 2024/8/25 15:19
+ */
+@Data
+@AllArgsConstructor
+public class MarkdownMessage implements JsonMessagePart {
+ /**
+ * Markdown格式数据
+ * @since 2024/8/25 15:20 v1.0.0
+ */
+ private String data;
+ @Override
+ public PartType getPartType() {
+ return PartType.MARKDOWN;
+ }
+
+ @Override
+ public JSONObject getData() {
+ return JSONObject.of("data", data);
+ }
+}
diff --git a/src/main/java/cn/wzpmc/api/message/json/parts/PartType.java b/src/main/java/cn/wzpmc/api/message/json/parts/PartType.java
index 7d6735e..915caf2 100644
--- a/src/main/java/cn/wzpmc/api/message/json/parts/PartType.java
+++ b/src/main/java/cn/wzpmc/api/message/json/parts/PartType.java
@@ -113,7 +113,12 @@ public enum PartType {
* JSON消息
* @since 2024/8/23 21:40 v0.0.5-dev
*/
- JSON(CustomJSONMessage.class);
+ JSON(CustomJSONMessage.class),
+ /**
+ * Markdown消息
+ * @since 2024/8/25 15:20 v1.0.0
+ */
+ MARKDOWN(MarkdownMessage.class);
public final Class extends JsonMessagePart> clazz;
PartType(Class extends JsonMessagePart> clazz){
this.clazz = clazz;
diff --git a/src/main/java/cn/wzpmc/api/user/IBot.java b/src/main/java/cn/wzpmc/api/user/IBot.java
index 2bca0d1..1d98eb5 100644
--- a/src/main/java/cn/wzpmc/api/user/IBot.java
+++ b/src/main/java/cn/wzpmc/api/user/IBot.java
@@ -1,6 +1,7 @@
package cn.wzpmc.api.user;
import cn.wzpmc.api.api.IMainApi;
+import cn.wzpmc.api.entities.Ops;
import cn.wzpmc.api.events.Event;
import cn.wzpmc.api.plugins.ICommandManager;
import cn.wzpmc.api.plugins.configuration.IConfiguration;
@@ -105,4 +106,70 @@ public abstract class IBot extends MessageSender implements CommandSender {
}
throw new RuntimeException(new IllegalAccessException("Shouldn't set id after initialized"));
}
+
+ /**
+ * 获取OP列表
+ * @author wzp
+ * @since 2024/8/25 14:11 v1.0.0
+ * @return OP列表
+ */
+ abstract public Ops getOps();
+
+ /**
+ * 添加一个OP用户
+ * @author wzp
+ * @since 2024/8/25 14:12 v1.0.0
+ * @param userId 用户ID
+ */
+ abstract public void addOp(Long userId);
+
+ /**
+ * 为一个群添加OP用户
+ * @author wzp
+ * @since 2024/8/25 20:21 v1.0.0
+ * @param groupId 群ID
+ * @param userId 用户ID
+ */
+ abstract public void addOp(Long groupId, Long userId);
+
+ /**
+ * 移除一个用户的OP身份
+ * @author wzp
+ * @since 2024/8/25 20:23 v1.0.0
+ * @param userId 用户ID
+ * @return 是否移除
+ */
+ abstract public boolean removeOp(Long userId);
+ /**
+ * 移除一个用户在群内的OP身份
+ * @author wzp
+ * @since 2024/8/25 20:23 v1.0.0
+ * @param groupId 群ID
+ * @param userId 用户ID
+ * @return 是否移除
+ */
+ abstract public boolean removeOp(Long groupId, Long userId);
+
+ /**
+ * 检查用户是否为OP
+ * @author wzp
+ * @since 2024/8/25 14:10 v1.0.0
+ * @param userId 用户ID
+ * @return 是否为OP
+ */
+ public boolean isBotOp(Long userId){
+ return getOps().isAdmin(userId);
+ }
+
+ /**
+ * 检查用户在群内是否为OP
+ * @author wzp
+ * @since 2024/8/25 20:22 v1.0.0
+ * @param groupId 群ID
+ * @param userId 用户ID
+ * @return 是否为OP
+ */
+ public boolean isBotOp(Long groupId, Long userId) {
+ return this.getOps().isAdmin(groupId, userId);
+ }
}
diff --git a/src/main/java/cn/wzpmc/api/user/group/GroupCommandSender.java b/src/main/java/cn/wzpmc/api/user/group/GroupCommandSender.java
index 2c37c5d..5f3c473 100644
--- a/src/main/java/cn/wzpmc/api/user/group/GroupCommandSender.java
+++ b/src/main/java/cn/wzpmc/api/user/group/GroupCommandSender.java
@@ -12,6 +12,7 @@ import cn.wzpmc.api.user.CommandSender;
import cn.wzpmc.api.user.IBot;
import cn.wzpmc.api.user.Sex;
import cn.wzpmc.api.user.permission.Permissions;
+import cn.wzpmc.entities.user.bot.MyBot;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -42,7 +43,7 @@ public class GroupCommandSender extends GroupUser implements CommandSender {
JsonMessage jsonMessage = new JsonMessage();
List messageParts = jsonMessage.getMessageParts();
messageParts.add(new At(this.getId()));
- messageParts.add(StringMessage.text(messageComponent.toMessageString()));
+ messageParts.add(StringMessage.text(" " + messageComponent.toMessageString()));
SendGroupMessageAction sendGroupMessageAction = new SendGroupMessageAction(this.groupId, jsonMessage);
mainApi.doApiCall(sendGroupMessageAction);
}
@@ -68,6 +69,10 @@ public class GroupCommandSender extends GroupUser implements CommandSender {
String level = sender.getLevel();
GroupUserRole role = sender.getRole();
String title = sender.getTitle();
+ IBot instance = MyBot.getInstance();
+ if (!permissions.isAdmin() && instance.isBotOp(eventGroupId, id)) {
+ permissions = Permissions.ADMIN;
+ }
return new GroupCommandSender(id, name, permissions, nickname, sex, age, card, area, level, role, title, eventGroupId);
}
}
diff --git a/src/main/java/cn/wzpmc/api/utils/CqCodeUtils.java b/src/main/java/cn/wzpmc/api/utils/CqCodeUtils.java
new file mode 100644
index 0000000..7108d80
--- /dev/null
+++ b/src/main/java/cn/wzpmc/api/utils/CqCodeUtils.java
@@ -0,0 +1,148 @@
+package cn.wzpmc.api.utils;
+
+import cn.wzpmc.api.message.json.JsonMessagePart;
+import cn.wzpmc.api.message.json.parts.PartType;
+import cn.wzpmc.api.message.json.parts.music.MusicType;
+import cn.wzpmc.api.message.json.parts.node.CustomNode;
+import cn.wzpmc.api.message.json.parts.node.SingleNode;
+import cn.wzpmc.api.message.json.parts.poke.Poke;
+import cn.wzpmc.api.message.json.parts.poke.PokeType;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.alibaba.fastjson2.annotation.JSONField;
+import lombok.SneakyThrows;
+import lombok.extern.log4j.Log4j2;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * CQ码相关工具类
+ * @author wzp
+ * @version 1.0.0
+ * @since 2024/8/26 14:06
+ */
+@Log4j2
+public class CqCodeUtils {
+ /**
+ * 判断一个字符串是否为CQ码
+ * @author wzp
+ * @since 2024/8/26 14:08 v1.0.0
+ * @param word 一个词(不包含空格)
+ * @return 是否为CQ码
+ */
+ public static boolean isCQ(String word){
+ return word.startsWith("[") && word.endsWith("]");
+ }
+
+ /**
+ * 解析CQ码为Map
+ * @author wzp
+ * @since 2024/8/26 14:08 v1.0.0
+ * @param word 一个词(不包含空格)
+ * @return 解析后的Map
+ */
+ public static Map parse(String word){
+ StringBuilder key = new StringBuilder();
+ boolean keyDone = false;
+ StringBuilder value = new StringBuilder();
+ Map result = new HashMap<>();
+ for (int i = 0; i < word.length(); i++) {
+ char c = word.charAt(i);
+ if (c == '[') continue;
+ if (c == ']') {
+ result.put(key.toString(), value.toString());
+ }
+ if (keyDone) {
+ if (c == ','){
+ result.put(key.toString(), value.toString());
+ key = new StringBuilder();
+ value = new StringBuilder();
+ keyDone = false;
+ continue;
+ }
+ value.append(c);
+ continue;
+ }
+ if (c == ':' || c == '='){
+ keyDone = true;
+ continue;
+ }
+ key.append(c);
+ }
+ return result;
+ }
+
+ /**
+ * 将文本转化为JsonMessagePart
+ * @author wzp
+ * @since 2024/8/26 14:34 v1.0.0
+ * @param word 一个词(不包含空格)
+ * @return 消息文本段
+ */
+ @SneakyThrows
+ public static JsonMessagePart parseToPart(String word) {
+ Map parse = parse(word);
+ JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(parse));
+ Object cq = jsonObject.get("CQ");
+ JSONObject jsonObj = JSONObject.of("type", cq, "data", jsonObject);
+ return parsePart(jsonObj);
+ }
+ /**
+ * 将json解析为单个消息段
+ * @author wzp
+ * @since 2024/8/26 14:40 v1.0.0
+ * @param jsonObject json数据
+ * @return 消息段
+ * @throws InvocationTargetException 调用构造方法失败时抛出
+ * @throws InstantiationException 实例化错误时抛出
+ * @throws IllegalAccessException 实例化错误时抛出
+ * @throws NoSuchMethodException 找不到构造方法时抛出
+ */
+ public static JsonMessagePart parsePart(JSONObject jsonObject) throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
+ PartType type = jsonObject.getObject("type", PartType.class);
+ Class extends JsonMessagePart> clazz = type.clazz;
+ JSONObject dataObject = jsonObject.getJSONObject("data");
+ if (type.equals(PartType.POKE)){
+ Integer pokeType = dataObject.getInteger("type");
+ Integer pokeId = dataObject.getInteger("id");
+ for (PokeType value : PokeType.values()) {
+ if (value.type.equals(pokeType) && value.id.equals(pokeId)){
+ return new Poke(value);
+ }
+ }
+ log.warn("无法识别的戳一戳类型:type: {}, id: {}", pokeType, pokeId);
+ return new Poke();
+ }
+ if (type.equals(PartType.NODE)){
+ if (jsonObject.containsKey("content")){
+ clazz = CustomNode.class;
+ }else{
+ clazz = SingleNode.class;
+ }
+ }
+ if (type.equals(PartType.MUSIC)){
+ MusicType musicType = dataObject.getObject("type", MusicType.class);
+ dataObject.put("musicType", musicType);
+ clazz = musicType.clazz;
+ }
+ Constructor extends JsonMessagePart> declaredConstructor = clazz.getDeclaredConstructor();
+ JsonMessagePart resultPart = declaredConstructor.newInstance();
+ for (Field declaredField : clazz.getDeclaredFields()) {
+ JSONField annotation = declaredField.getAnnotation(JSONField.class);
+ String name = Objects.isNull(annotation) ? declaredField.getName() : annotation.name();
+ if (!dataObject.containsKey(name)) {
+ continue;
+ }
+ declaredField.setAccessible(true);
+ Class> thisFieldClass = declaredField.getType();
+ Object value = dataObject.getObject(name, thisFieldClass);
+ declaredField.set(resultPart, value);
+ }
+ return resultPart;
+ }
+}
diff --git a/src/main/java/cn/wzpmc/api/utils/IncreasbleHashMap.java b/src/main/java/cn/wzpmc/api/utils/IncreasbleHashMap.java
index 3bc30bc..e81bf0e 100644
--- a/src/main/java/cn/wzpmc/api/utils/IncreasbleHashMap.java
+++ b/src/main/java/cn/wzpmc/api/utils/IncreasbleHashMap.java
@@ -11,7 +11,7 @@ import java.util.List;
* @version 0.0.4-dev
* @since 2024/8/16 00:02
*/
-public class IncreasbleHashMap extends HashMap> implements IncreasbleMap{
+public class IncreasbleHashMap extends HashMap> implements IncreasbleMap>{
@Override
public void add(K key, V value) {
List newArrayList = super.getOrDefault(key, new ArrayList<>());
@@ -41,7 +41,7 @@ public class IncreasbleHashMap extends HashMap> implements Incr
}
@Override
- public void addAll(IncreasbleMap increasbleMap) {
+ public void addAll(IncreasbleMap> increasbleMap) {
for (Entry> entry : increasbleMap.entrySet()) {
this.addAll(entry.getKey(), entry.getValue());
}
diff --git a/src/main/java/cn/wzpmc/api/utils/IncreasbleMap.java b/src/main/java/cn/wzpmc/api/utils/IncreasbleMap.java
index ef13bf2..3a823ec 100644
--- a/src/main/java/cn/wzpmc/api/utils/IncreasbleMap.java
+++ b/src/main/java/cn/wzpmc/api/utils/IncreasbleMap.java
@@ -1,7 +1,6 @@
package cn.wzpmc.api.utils;
import java.util.Collection;
-import java.util.List;
import java.util.Map;
/**
@@ -9,8 +8,11 @@ import java.util.Map;
* @author wzp
* @version 0.0.4-dev
* @since 2024/8/15 23:57
+ * @param 集合类型
+ * @param key类型
+ * @param value类型
*/
-public interface IncreasbleMap extends Map> {
+public interface IncreasbleMap> extends Map {
/**
* 向一个Key中添加元素
* @author wzp
@@ -45,7 +47,7 @@ public interface IncreasbleMap extends Map> {
* @since 2024/8/16 00:35 v0.0.4-dev
* @param increasbleMap 另一个表
*/
- void addAll(IncreasbleMap increasbleMap);
+ void addAll(IncreasbleMap increasbleMap);
/**
* 将所有value添加到此key中
diff --git a/src/main/java/cn/wzpmc/builtin/commands/DeOpCommand.java b/src/main/java/cn/wzpmc/builtin/commands/DeOpCommand.java
new file mode 100644
index 0000000..8a11b4c
--- /dev/null
+++ b/src/main/java/cn/wzpmc/builtin/commands/DeOpCommand.java
@@ -0,0 +1,77 @@
+package cn.wzpmc.builtin.commands;
+
+import cn.wzpmc.api.commands.BrigadierCommand;
+import cn.wzpmc.api.commands.arguments.UserIdArguments;
+import cn.wzpmc.api.entities.Ops;
+import cn.wzpmc.api.message.StringMessage;
+import cn.wzpmc.api.user.CommandSender;
+import cn.wzpmc.api.user.IBot;
+import cn.wzpmc.api.user.group.GroupCommandSender;
+import cn.wzpmc.entities.user.bot.MyBot;
+import com.mojang.brigadier.arguments.LongArgumentType;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+
+/**
+ * @author wzp
+ * @version 1.0.0
+ * @since 2024/8/26 16:54
+ */
+public class DeOpCommand implements BrigadierCommand {
+ private final IBot instance;
+ public DeOpCommand(){
+ this.instance = MyBot.getInstance();
+ }
+ @Override
+ public LiteralArgumentBuilder getCommandNode() {
+ return LiteralArgumentBuilder.
+ literal("deop").
+ requires(CommandSender::isAdmin).
+ then(RequiredArgumentBuilder.argument("user", new UserIdArguments()).
+ executes(e -> {
+ Ops ops = instance.getOps();
+ CommandSender source = e.getSource();
+ Long targetId = e.getArgument("user", Long.class);
+ if (source instanceof GroupCommandSender){
+ if (ops.isAdmin(source.getId())){
+ instance.removeOp(targetId);
+ source.sendMessage(StringMessage.text("已为用户:" + targetId + "移除总OP权限"));
+ }else{
+ Long groupId = ((GroupCommandSender) source).getGroupId();
+ instance.removeOp(groupId, targetId);
+ source.sendMessage(StringMessage.text("已为用户:" + targetId + "移除群:" + groupId + "的OP权限"));
+ }
+ return 0;
+ }
+ instance.removeOp(targetId);
+ source.sendMessage(StringMessage.text("已为用户:" + targetId + "移除总OP权限"));
+ return 0;
+ }).
+ then(LiteralArgumentBuilder.literal("group")
+ .then(RequiredArgumentBuilder.argument("group", LongArgumentType.longArg()).
+ executes(e -> {
+ Long targetGroupId = e.getArgument("group", Long.class);
+ Long targetId = e.getArgument("user", Long.class);
+ CommandSender source = e.getSource();
+ if (source instanceof GroupCommandSender){
+ if (!instance.isBotOp(targetGroupId, source.getId())) {
+ source.sendMessage(StringMessage.text("权限不足!"));
+ return 0;
+ }
+ }
+ instance.removeOp(targetGroupId, targetId);
+ source.sendMessage(StringMessage.text("已为用户:" + targetId + "移除群:" + targetGroupId + "的OP权限"));
+ return 0;
+ })
+ ).requires((e) -> e instanceof GroupCommandSender).executes(e -> {
+ GroupCommandSender source = (GroupCommandSender) e.getSource();
+ Long groupId = source.getGroupId();
+ Long targetId = e.getArgument("user", Long.class);
+ instance.removeOp(groupId, targetId);
+ source.sendMessage(StringMessage.text("已为用户:" + targetId + "移除群:" + groupId + "的OP权限"));
+ return 0;
+ })
+ )
+ );
+ }
+}
diff --git a/src/main/java/cn/wzpmc/builtin/commands/HelpCommand.java b/src/main/java/cn/wzpmc/builtin/commands/HelpCommand.java
new file mode 100644
index 0000000..c588c04
--- /dev/null
+++ b/src/main/java/cn/wzpmc/builtin/commands/HelpCommand.java
@@ -0,0 +1,58 @@
+package cn.wzpmc.builtin.commands;
+
+import cn.wzpmc.api.commands.BrigadierCommand;
+import cn.wzpmc.api.commands.RawCommand;
+import cn.wzpmc.api.message.StringMessage;
+import cn.wzpmc.api.user.CommandSender;
+import cn.wzpmc.api.user.IBot;
+import cn.wzpmc.entities.user.bot.MyBot;
+import cn.wzpmc.plugins.CommandManager;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.tree.CommandNode;
+import com.mojang.brigadier.tree.RootCommandNode;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * @author wzp
+ * @version 1.0.0
+ * @since 2024/8/25 15:07
+ */
+public class HelpCommand implements BrigadierCommand {
+ @Override
+ public LiteralArgumentBuilder getCommandNode() {
+ return LiteralArgumentBuilder.literal("help").executes(e -> {
+ IBot instance = MyBot.getInstance();
+ CommandManager commandManager = (CommandManager) instance.getCommandManager();
+ CommandDispatcher dispatcher = commandManager.getDispatcher();
+ RootCommandNode root = dispatcher.getRoot();
+ Collection> children = root.getChildren();
+ CommandSender source = e.getSource();
+ for (CommandNode child : children) {
+ StringBuilder builder = new StringBuilder();
+ builder.append('\n');
+ builder.append('/');
+ builder.append(child.getUsageText());
+ builder.append('\n');
+ handlerNode(child.getChildren(), 1, builder);
+ source.sendMessage(StringMessage.text(builder.toString()));
+ }
+ ConcurrentHashMap rawCommands = commandManager.getRawCommands();
+ for (Map.Entry stringRawCommandEntry : rawCommands.entrySet()) {
+ source.sendMessage(StringMessage.text("/" + stringRawCommandEntry.getKey()));
+ }
+ return 0;
+ });
+ }
+ private static void handlerNode(Collection> node, int tabCount, StringBuilder builder){
+ for (CommandNode commandSenderCommandNode : node) {
+ builder.append("\t".repeat(Math.max(0, tabCount)));
+ builder.append(commandSenderCommandNode.getUsageText());
+ builder.append('\n');
+ handlerNode(commandSenderCommandNode.getChildren(), tabCount + 1, builder);
+ }
+ }
+}
diff --git a/src/main/java/cn/wzpmc/builtin/commands/OpCommand.java b/src/main/java/cn/wzpmc/builtin/commands/OpCommand.java
new file mode 100644
index 0000000..4e34685
--- /dev/null
+++ b/src/main/java/cn/wzpmc/builtin/commands/OpCommand.java
@@ -0,0 +1,183 @@
+package cn.wzpmc.builtin.commands;
+
+import cn.wzpmc.api.commands.BrigadierCommand;
+import cn.wzpmc.api.commands.arguments.UserIdArguments;
+import cn.wzpmc.api.entities.Ops;
+import cn.wzpmc.api.message.StringMessage;
+import cn.wzpmc.api.user.CommandSender;
+import cn.wzpmc.api.user.IBot;
+import cn.wzpmc.api.user.group.GroupCommandSender;
+import cn.wzpmc.entities.user.bot.MyBot;
+import com.mojang.brigadier.arguments.LongArgumentType;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+
+import java.util.*;
+
+/**
+ * @author wzp
+ * @version 1.0.0
+ * @since 2024/8/25 15:35
+ */
+public class OpCommand implements BrigadierCommand {
+ private final IBot instance;
+ public OpCommand(){
+ this.instance = MyBot.getInstance();
+ }
+ @Override
+ public LiteralArgumentBuilder getCommandNode() {
+ return LiteralArgumentBuilder.
+ literal("op").
+ then(LiteralArgumentBuilder.literal("list").executes(e -> {
+ Ops ops = instance.getOps();
+ Map> groupAdmins = ops.getGroupAdmins();
+ Set fullAdmins = ops.getAdmins();
+ CommandSender source = e.getSource();
+ Long id = source.getId();
+ boolean groupAdmin = false;
+ boolean fullAdmin = fullAdmins.contains(id);
+ Long sendGroupId = -1L;
+ List sendGroupAdmins = new ArrayList<>();
+ if (source instanceof GroupCommandSender) {
+ sendGroupId = ((GroupCommandSender) source).getGroupId();
+ List orDefault = groupAdmins.getOrDefault(sendGroupId.toString(), new ArrayList<>());
+ sendGroupAdmins.addAll(orDefault);
+ groupAdmin = orDefault.contains(id);
+ }
+ if (source instanceof IBot) {
+ groupAdmin = true;
+ fullAdmin = true;
+ }
+ StringBuilder builder = new StringBuilder();
+ if (fullAdmin){
+ builder.append(getFullOpListString(fullAdmins)).append('\n');
+ for (Map.Entry> stringListEntry : groupAdmins.entrySet()) {
+ builder.append(getGroupOpListString(stringListEntry.getValue(), Long.valueOf(stringListEntry.getKey()))).append('\n');
+ }
+ builder.deleteCharAt(builder.lastIndexOf("\n"));
+
+ }else if (groupAdmin) {
+ builder.append(getGroupOpListString(sendGroupAdmins, sendGroupId));
+ }else {
+ builder.append("权限不足!");
+ }
+ source.sendMessage(StringMessage.text(builder.toString()));
+ return 0;
+ }).then(LiteralArgumentBuilder.literal("group").
+ then(RequiredArgumentBuilder.argument("groupId", LongArgumentType.longArg()).
+ executes(e -> {
+ Long groupId = e.getArgument("groupId", Long.class);
+ Ops ops = instance.getOps();
+ Map> groupsAdmins = ops.getGroupAdmins();
+ Set admins = ops.getAdmins();
+ List groupAdmins = groupsAdmins.getOrDefault(groupId.toString(), new ArrayList<>());
+ CommandSender source = e.getSource();
+ Long id = source.getId();
+ String result = "权限不足";
+ if (source instanceof IBot || admins.contains(id) || groupAdmins.contains(id)) {
+ result = getGroupOpListString(groupAdmins, groupId);
+ }
+ source.sendMessage(StringMessage.text(result));
+ return 0;
+ })).
+ executes(e -> {
+ CommandSender commandSender = e.getSource();
+ if (!(commandSender instanceof GroupCommandSender)) {
+ commandSender.sendMessage(StringMessage.text("仅支持群内使用此指令!"));
+ return 0;
+ }
+ GroupCommandSender source = (GroupCommandSender) commandSender;
+ Long groupId = source.getGroupId();
+ Ops ops = instance.getOps();
+ Map> groupsAdmins = ops.getGroupAdmins();
+ Set admins = ops.getAdmins();
+ List groupAdmins = groupsAdmins.getOrDefault(groupId.toString(), new ArrayList<>());
+ Long id = source.getId();
+ String result = "权限不足";
+ if (admins.contains(id) || groupAdmins.contains(id)) {
+ result = getGroupOpListString(groupAdmins, groupId);
+ }
+ source.sendMessage(StringMessage.text(result));
+ return 0;
+ })
+ ).then(LiteralArgumentBuilder.literal("full").executes(e -> {
+ Ops ops = instance.getOps();
+ Set admins = ops.getAdmins();
+ CommandSender source = e.getSource();
+ Long id = source.getId();
+ String result = "权限不足";
+ if (source instanceof IBot || admins.contains(id)) {
+ result = getFullOpListString(admins);
+ }
+ source.sendMessage(StringMessage.text(result));
+ return 0;
+ }))).
+ requires(CommandSender::isAdmin).
+ then(RequiredArgumentBuilder.argument("user", new UserIdArguments()).
+ executes(e -> {
+ Ops ops = instance.getOps();
+ CommandSender source = e.getSource();
+ Long targetId = e.getArgument("user", Long.class);
+ if (source instanceof GroupCommandSender){
+ if (ops.isAdmin(source.getId())){
+ instance.addOp(targetId);
+ source.sendMessage(StringMessage.text("已为用户:" + targetId + "添加总OP权限"));
+ }else{
+ Long groupId = ((GroupCommandSender) source).getGroupId();
+ instance.addOp(groupId, targetId);
+ source.sendMessage(StringMessage.text("已为用户:" + targetId + "添加群:" + groupId + "的OP权限"));
+ }
+ return 0;
+ }
+ instance.addOp(targetId);
+ source.sendMessage(StringMessage.text("已为用户:" + targetId + "添加总OP权限"));
+ return 0;
+ }).
+ then(LiteralArgumentBuilder.literal("group")
+ .then(RequiredArgumentBuilder.argument("group", LongArgumentType.longArg()).
+ executes(e -> {
+ Long targetGroupId = e.getArgument("group", Long.class);
+ Long targetId = e.getArgument("user", Long.class);
+ CommandSender source = e.getSource();
+ if (source instanceof GroupCommandSender){
+ if (!instance.isBotOp(targetGroupId, source.getId())) {
+ source.sendMessage(StringMessage.text("权限不足!"));
+ return 0;
+ }
+ }
+ instance.addOp(targetGroupId, targetId);
+ source.sendMessage(StringMessage.text("已为用户:" + targetId + "添加群:" + targetGroupId + "的OP权限"));
+ return 0;
+ })
+ ).requires((e) -> e instanceof GroupCommandSender).executes(e -> {
+ GroupCommandSender source = (GroupCommandSender) e.getSource();
+ Long groupId = source.getGroupId();
+ Long targetId = e.getArgument("user", Long.class);
+ instance.addOp(groupId, targetId);
+ source.sendMessage(StringMessage.text("已为用户:" + targetId + "添加群:" + groupId + "的OP权限"));
+ return 0;
+ })
+ )
+ );
+ }
+ private static String getFullOpListString(Collection admins){
+ return "总管理:" + '\n' +
+ getOpListString(admins);
+ }
+ private static String getGroupOpListString(Collection admins, Long groupId){
+ return "群" + groupId + "的管理员:" + '\n' +
+ getOpListString(admins);
+ }
+ private static StringBuilder getOpListString(Collection admins) {
+ StringBuilder builder = new StringBuilder();
+ if (admins.isEmpty()){
+ builder.append("无").append('\n');
+ }
+ for (Long admin : admins) {
+ builder.append('\t').append(admin).append('\n');
+ }
+ int lastLine = builder.lastIndexOf("\n");
+ builder.deleteCharAt(lastLine);
+ return builder;
+ }
+}
diff --git a/src/main/java/cn/wzpmc/commands/StopCommand.java b/src/main/java/cn/wzpmc/builtin/commands/StopCommand.java
similarity index 57%
rename from src/main/java/cn/wzpmc/commands/StopCommand.java
rename to src/main/java/cn/wzpmc/builtin/commands/StopCommand.java
index 1ea2f84..57e5094 100644
--- a/src/main/java/cn/wzpmc/commands/StopCommand.java
+++ b/src/main/java/cn/wzpmc/builtin/commands/StopCommand.java
@@ -1,11 +1,15 @@
-package cn.wzpmc.commands;
+package cn.wzpmc.builtin.commands;
import cn.wzpmc.api.commands.BrigadierCommand;
+import cn.wzpmc.api.entities.Ops;
+import cn.wzpmc.api.message.StringMessage;
import cn.wzpmc.api.user.CommandSender;
import cn.wzpmc.api.user.IBot;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import lombok.RequiredArgsConstructor;
+import java.util.Set;
+
/**
* /stop指令
* @author wzp
@@ -18,9 +22,16 @@ public class StopCommand implements BrigadierCommand {
@Override
public LiteralArgumentBuilder getCommandNode() {
return LiteralArgumentBuilder.literal("stop")
- .requires(CommandSender::isAdmin)
+ .requires(e -> {
+ Ops ops = bot.getOps();
+ Set admins = ops.getAdmins();
+ return admins.contains(e.getId());
+ })
.executes((e) -> {
+ CommandSender source = e.getSource();
+ source.sendMessage(StringMessage.text(" !!!MyBot已关闭!!!"));
this.bot.stop();
+ System.exit(0);
return 0;
});
}
diff --git a/src/main/java/cn/wzpmc/builtin/event/CommandEventHandler.java b/src/main/java/cn/wzpmc/builtin/event/CommandEventHandler.java
new file mode 100644
index 0000000..91ecdcd
--- /dev/null
+++ b/src/main/java/cn/wzpmc/builtin/event/CommandEventHandler.java
@@ -0,0 +1,45 @@
+package cn.wzpmc.builtin.event;
+
+import cn.wzpmc.api.events.message.group.GroupMessageEvent;
+import cn.wzpmc.api.events.message.priv.PrivateMessageEvent;
+import cn.wzpmc.api.message.StringMessage;
+import cn.wzpmc.api.plugins.event.EventHandler;
+import cn.wzpmc.api.user.Friend;
+import cn.wzpmc.api.user.IBot;
+import cn.wzpmc.api.user.group.GroupCommandSender;
+import cn.wzpmc.entities.user.bot.MyBot;
+import cn.wzpmc.plugins.CommandManager;
+
+import java.util.regex.Pattern;
+
+/**
+ * 命令事件处理器
+ * @author wzp
+ * @version 1.0.0
+ * @since 2024/8/25 13:40
+ */
+public class CommandEventHandler {
+ @EventHandler
+ public void onGroupMessage(GroupMessageEvent event){
+ GroupCommandSender groupCommandSender = GroupCommandSender.of(event);
+ IBot instance = MyBot.getInstance();
+ Long id = instance.getId();
+ String message = event.getRawMessage().getMessage();
+ Pattern compile = Pattern.compile("\\[CQ:at,qq=" + id + ".*?]\\s*?/.*");
+ if (compile.asMatchPredicate().test(message)){
+ CommandManager commandManager = (CommandManager) instance.getCommandManager();
+ commandManager.execute(groupCommandSender, message.replaceFirst("\\[CQ:at,qq=[0-9]{10}.*?]\\s*?/", ""));
+ }
+ }
+ @EventHandler
+ public void onPrivateMessage(PrivateMessageEvent event){
+ Friend sender = event.getSender();
+ IBot instance = MyBot.getInstance();
+ StringMessage rawMessage = event.getRawMessage();
+ String message = rawMessage.getMessage();
+ if (message.startsWith("/")){
+ CommandManager commandManager = (CommandManager) instance.getCommandManager();
+ commandManager.execute(sender, message.replaceFirst("/", ""));
+ }
+ }
+}
diff --git a/src/main/java/cn/wzpmc/console/MyBotConsole.java b/src/main/java/cn/wzpmc/console/MyBotConsole.java
index 5fe6faa..160ad41 100644
--- a/src/main/java/cn/wzpmc/console/MyBotConsole.java
+++ b/src/main/java/cn/wzpmc/console/MyBotConsole.java
@@ -1,10 +1,8 @@
package cn.wzpmc.console;
-import cn.wzpmc.api.plugins.BasePlugin;
import cn.wzpmc.entities.user.bot.MyBot;
import cn.wzpmc.network.WebSocketConnectionHandler;
import cn.wzpmc.plugins.CommandManager;
-import cn.wzpmc.plugins.PluginManager;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
@@ -46,8 +44,6 @@ public class MyBotConsole extends SimpleTerminalConsole {
@Override
public void shutdown() {
- PluginManager pluginManager = this.bot.getPluginManager();
- pluginManager.getPlugins().forEach(BasePlugin::onUnload);
this.webSocketConnectionHandler.kill();
running = false;
}
diff --git a/src/main/java/cn/wzpmc/console/commands/exceptions/CqCodeException.java b/src/main/java/cn/wzpmc/console/commands/exceptions/CqCodeException.java
new file mode 100644
index 0000000..e3c3d5a
--- /dev/null
+++ b/src/main/java/cn/wzpmc/console/commands/exceptions/CqCodeException.java
@@ -0,0 +1,24 @@
+package cn.wzpmc.console.commands.exceptions;
+
+import com.mojang.brigadier.LiteralMessage;
+import com.mojang.brigadier.Message;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+
+/**
+ * @author wzp
+ * @version 1.0.0
+ * @since 2024/8/25 21:06
+ */
+public class CqCodeException extends CommandSyntaxException {
+ private static final Message errorMessage = new LiteralMessage("Cannot read cq code");
+ public CqCodeException() {
+ super(new CqCodeExceptionType(errorMessage), errorMessage);
+
+ }
+ private static final class CqCodeExceptionType extends SimpleCommandExceptionType {
+ public CqCodeExceptionType(Message message) {
+ super(message);
+ }
+ }
+}
diff --git a/src/main/java/cn/wzpmc/entities/user/bot/MyBot.java b/src/main/java/cn/wzpmc/entities/user/bot/MyBot.java
index 427afe4..4bc8360 100644
--- a/src/main/java/cn/wzpmc/entities/user/bot/MyBot.java
+++ b/src/main/java/cn/wzpmc/entities/user/bot/MyBot.java
@@ -1,6 +1,10 @@
package cn.wzpmc.entities.user.bot;
+import cn.wzpmc.api.api.ActionResponse;
import cn.wzpmc.api.api.IMainApi;
+import cn.wzpmc.api.api.actions.message.get.GetGroupListAction;
+import cn.wzpmc.api.entities.GroupInformation;
+import cn.wzpmc.api.entities.Ops;
import cn.wzpmc.api.events.Event;
import cn.wzpmc.api.message.MessageComponent;
import cn.wzpmc.api.message.StringMessage;
@@ -17,13 +21,21 @@ import cn.wzpmc.plugins.CommandManager;
import cn.wzpmc.plugins.PluginManager;
import cn.wzpmc.plugins.api.MainApi;
import cn.wzpmc.utils.ReflectionUtils;
+import com.alibaba.fastjson2.JSON;
import lombok.Getter;
import lombok.Setter;
+import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
/**
* 机器人实现类
@@ -48,9 +60,36 @@ public class MyBot extends IBot {
@Getter
private IMainApi mainApi;
private WebSocketConnectionHandler connectionHandler;
+ @Getter
+ private final Ops ops;
+ private final File opFile;
public MyBot(Configuration configuration){
+ Ops opsTmp;
this.configuration = configuration;
this.permissions = Permissions.ADMIN;
+ this.opFile = new File("ops.json");
+ if (!this.opFile.isFile()) {
+ opsTmp = new Ops();
+ try {
+ if (!this.opFile.createNewFile()) {
+ log.error("无法创建OP文件!");
+ }
+ } catch (IOException e) {
+ log.error("创建OP文件失败!",e);
+ throw new RuntimeException(e);
+ }
+ } else {
+ try(FileInputStream fis = new FileInputStream(this.opFile)) {
+ opsTmp = JSON.parseObject(fis, Ops.class);
+ } catch (IOException e) {
+ log.error("读取OP文件失败!");
+ throw new RuntimeException(e);
+ }
+ }
+ if (opsTmp == null){
+ opsTmp = new Ops();
+ }
+ this.ops = opsTmp;
}
@Override
@@ -71,6 +110,7 @@ public class MyBot extends IBot {
if (this.console != null) {
this.console.shutdown();
}
+ this.flushOpsFile();
}
@Override
@@ -99,4 +139,77 @@ public class MyBot extends IBot {
this.connectionHandler = connectionHandler;
this.mainApi = new MainApi(this, this.connectionHandler);
}
+
+ @Override
+ public void addOp(Long userId) {
+ Set admins = this.ops.getAdmins();
+ admins.add(userId);
+ this.flushOpsFile();
+ }
+
+ @Override
+ public void addOp(Long groupId, Long userId) {
+ Map> admins = this.ops.getGroupAdmins();
+ String string = groupId.toString();
+ List longs = admins.getOrDefault(string, new ArrayList<>());
+ if (!longs.contains(userId)) {
+ longs.add(userId);
+ admins.put(string, longs);
+ this.flushOpsFile();
+ }
+ }
+
+ @Override
+ public boolean removeOp(Long userId) {
+ if (!this.ops.isAdmin(userId)) {
+ return false;
+ }
+ Set admins = this.ops.getAdmins();
+ admins.remove(userId);
+ flushOpsFile();
+ return true;
+ }
+
+ @SneakyThrows
+ @Override
+ public boolean removeOp(Long groupId, Long userId) {
+ boolean groupAdmin = this.ops.isAdmin(groupId, userId);
+ boolean admin = this.ops.isAdmin(userId);
+ if (!groupAdmin && !admin){
+ return false;
+ }
+ Map> admins = this.ops.getGroupAdmins();
+ String string = groupId.toString();
+ if (groupAdmin && !admin) {
+ List longs = admins.get(string);
+ longs.remove(userId);
+ admins.put(string, longs);
+ } else {
+ ActionResponse> listActionResponse = this.mainApi.doApiCall(new GetGroupListAction());
+ List data = listActionResponse.getData();
+ this.ops.getAdmins().remove(userId);
+ for (GroupInformation groupInformation : data) {
+ Long groupInformationGroupId = groupInformation.getGroupId();
+ if (groupInformationGroupId.equals(groupId)) {
+ continue;
+ }
+ String groupIdString = groupInformationGroupId.toString();
+ List orDefault = admins.getOrDefault(groupIdString, new ArrayList<>());
+ if (!orDefault.contains(userId)) {
+ orDefault.add(userId);
+ }
+ admins.put(groupIdString, orDefault);
+ }
+ }
+ flushOpsFile();
+ return true;
+ }
+
+ private void flushOpsFile() {
+ try(FileOutputStream fos = new FileOutputStream(this.opFile)){
+ JSON.writeTo(fos, this.ops);
+ } catch (IOException e) {
+ log.error("写入OP文件失败!", e);
+ }
+ }
}
diff --git a/src/main/java/cn/wzpmc/network/PacketHandler.java b/src/main/java/cn/wzpmc/network/PacketHandler.java
index 41516cd..25601f9 100644
--- a/src/main/java/cn/wzpmc/network/PacketHandler.java
+++ b/src/main/java/cn/wzpmc/network/PacketHandler.java
@@ -33,7 +33,7 @@ public class PacketHandler extends SimpleChannelInboundHandler dispatcher = new CommandDispatcher<>();
+ @Getter
private final ConcurrentHashMap rawCommands = new ConcurrentHashMap<>();
private static final int[] COLORS = {AttributedStyle.CYAN, AttributedStyle.YELLOW, AttributedStyle.GREEN, AttributedStyle.MAGENTA, AttributedStyle.BLUE};
private final IBot bot;
diff --git a/src/main/java/cn/wzpmc/utils/JsonUtils.java b/src/main/java/cn/wzpmc/utils/JsonUtils.java
index 2343a57..33c72a0 100644
--- a/src/main/java/cn/wzpmc/utils/JsonUtils.java
+++ b/src/main/java/cn/wzpmc/utils/JsonUtils.java
@@ -11,8 +11,10 @@ import cn.wzpmc.api.events.notice.notify.NotifyEvent;
import cn.wzpmc.api.events.request.RequestEvent;
import cn.wzpmc.api.message.StringMessage;
import cn.wzpmc.api.message.json.JsonMessage;
+import cn.wzpmc.api.user.Friend;
import cn.wzpmc.api.user.IBot;
import cn.wzpmc.api.user.IUser;
+import cn.wzpmc.api.user.group.GroupUser;
import cn.wzpmc.utils.json.action.ActionReader;
import cn.wzpmc.utils.json.action.ActionWriter;
import cn.wzpmc.utils.json.event.*;
@@ -20,6 +22,8 @@ import cn.wzpmc.utils.json.honor.HonorWriter;
import cn.wzpmc.utils.json.message.JsonMessageReader;
import cn.wzpmc.utils.json.message.JsonMessageWriter;
import cn.wzpmc.utils.json.message.StringMessageReader;
+import cn.wzpmc.utils.json.user.FriendUserReader;
+import cn.wzpmc.utils.json.user.GroupUserReader;
import cn.wzpmc.utils.json.user.IBotReader;
import cn.wzpmc.utils.json.user.IUserReader;
import com.alibaba.fastjson2.JSON;
@@ -59,6 +63,8 @@ public class JsonUtils {
JSON.register(ActionResponse.class, new ActionReader());
JSON.register(IUser.class, new IUserReader());
JSON.register(IBot.class, new IBotReader());
+ JSON.register(Friend.class, new FriendUserReader());
+ JSON.register(GroupUser.class, new GroupUserReader());
}
}
diff --git a/src/main/java/cn/wzpmc/utils/ReflectionUtils.java b/src/main/java/cn/wzpmc/utils/ReflectionUtils.java
index 0f382a5..18152e6 100644
--- a/src/main/java/cn/wzpmc/utils/ReflectionUtils.java
+++ b/src/main/java/cn/wzpmc/utils/ReflectionUtils.java
@@ -17,6 +17,7 @@ import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URLClassLoader;
+import java.util.List;
import java.util.Optional;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@@ -69,9 +70,9 @@ public class ReflectionUtils {
return null;
}
}
- public static IncreasbleMap, EventHandlerMethod> loadEvents(Object eventHandlerObject){
+ public static IncreasbleMap, EventHandlerMethod, List> loadEvents(Object eventHandlerObject){
Class> eventHandlerClass = eventHandlerObject.getClass();
- IncreasbleMap, EventHandlerMethod> result = new IncreasbleHashMap<>();
+ IncreasbleMap, EventHandlerMethod, List> result = new IncreasbleHashMap<>();
for (Method declaredMethod : eventHandlerClass.getDeclaredMethods()) {
declaredMethod.setAccessible(true);
if (!declaredMethod.isAnnotationPresent(EventHandler.class)){
diff --git a/src/main/java/cn/wzpmc/utils/json/message/JsonMessageReader.java b/src/main/java/cn/wzpmc/utils/json/message/JsonMessageReader.java
index a29d46d..1984a93 100644
--- a/src/main/java/cn/wzpmc/utils/json/message/JsonMessageReader.java
+++ b/src/main/java/cn/wzpmc/utils/json/message/JsonMessageReader.java
@@ -2,25 +2,16 @@ package cn.wzpmc.utils.json.message;
import cn.wzpmc.api.message.json.JsonMessage;
import cn.wzpmc.api.message.json.JsonMessagePart;
-import cn.wzpmc.api.message.json.parts.PartType;
-import cn.wzpmc.api.message.json.parts.music.MusicType;
-import cn.wzpmc.api.message.json.parts.node.CustomNode;
-import cn.wzpmc.api.message.json.parts.node.SingleNode;
-import cn.wzpmc.api.message.json.parts.poke.Poke;
-import cn.wzpmc.api.message.json.parts.poke.PokeType;
+import cn.wzpmc.api.utils.CqCodeUtils;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONReader;
-import com.alibaba.fastjson2.annotation.JSONField;
import com.alibaba.fastjson2.reader.ObjectReader;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.List;
-import java.util.Objects;
/**
* json消息解析器
@@ -36,49 +27,9 @@ public class JsonMessageReader implements ObjectReader {
JSONArray objects = jsonReader.readJSONArray();
JsonMessage message = new JsonMessage();
List messageParts = message.getMessageParts();
- messageFor: for (int i = 0; i < objects.size(); i++) {
+ for (int i = 0; i < objects.size(); i++) {
JSONObject jsonObject = objects.getJSONObject(i);
- PartType type = jsonObject.getObject("type", PartType.class);
- Class extends JsonMessagePart> clazz = type.clazz;
- JSONObject dataObject = jsonObject.getJSONObject("data");
- if (type.equals(PartType.POKE)){
- Integer pokeType = dataObject.getInteger("type");
- Integer pokeId = dataObject.getInteger("id");
- for (PokeType value : PokeType.values()) {
- if (value.type.equals(pokeType) && value.id.equals(pokeId)){
- messageParts.add(new Poke(value));
- continue messageFor;
- }
- }
- log.warn("无法识别的戳一戳类型:type: {}, id: {}", pokeType, pokeId);
- messageParts.add(new Poke());
- }
- if (type.equals(PartType.NODE)){
- if (jsonObject.containsKey("content")){
- clazz = CustomNode.class;
- }else{
- clazz = SingleNode.class;
- }
- }
- if (type.equals(PartType.MUSIC)){
- MusicType musicType = dataObject.getObject("type", MusicType.class);
- dataObject.put("musicType", musicType);
- clazz = musicType.clazz;
- }
- Constructor extends JsonMessagePart> declaredConstructor = clazz.getDeclaredConstructor();
- JsonMessagePart resultPart = declaredConstructor.newInstance();
- for (Field declaredField : clazz.getDeclaredFields()) {
- JSONField annotation = declaredField.getAnnotation(JSONField.class);
- String name = Objects.isNull(annotation) ? declaredField.getName() : annotation.name();
- if (!dataObject.containsKey(name)) {
- continue;
- }
- declaredField.setAccessible(true);
- Class> thisFieldClass = declaredField.getType();
- Object value = dataObject.getObject(name, thisFieldClass);
- declaredField.set(resultPart, value);
- }
- messageParts.add(resultPart);
+ messageParts.add(CqCodeUtils.parsePart(jsonObject));
}
return message;
}
diff --git a/src/main/java/cn/wzpmc/utils/json/user/FriendUserReader.java b/src/main/java/cn/wzpmc/utils/json/user/FriendUserReader.java
new file mode 100644
index 0000000..b37383f
--- /dev/null
+++ b/src/main/java/cn/wzpmc/utils/json/user/FriendUserReader.java
@@ -0,0 +1,35 @@
+package cn.wzpmc.utils.json.user;
+
+import cn.wzpmc.api.user.Friend;
+import cn.wzpmc.api.user.IBot;
+import cn.wzpmc.api.user.permission.Permissions;
+import cn.wzpmc.entities.user.bot.MyBot;
+import com.alibaba.fastjson2.JSONFactory;
+import com.alibaba.fastjson2.JSONReader;
+import com.alibaba.fastjson2.reader.ObjectReader;
+import com.alibaba.fastjson2.reader.ObjectReaderCreator;
+import com.alibaba.fastjson2.reader.ObjectReaderProvider;
+
+import java.lang.reflect.Type;
+
+/**
+ * @author wzp
+ * @version 1.0.0
+ * @since 2024/8/25 15:08
+ */
+public class FriendUserReader implements ObjectReader {
+ @Override
+ public Friend readObject(JSONReader jsonReader, Type type, Object o, long l) {
+ ObjectReaderProvider defaultObjectReaderProvider = JSONFactory.getDefaultObjectReaderProvider();
+ ObjectReaderCreator creator = defaultObjectReaderProvider.getCreator();
+ ObjectReader objectReader = creator.createObjectReader(Friend.class);
+ Friend friend = objectReader.readObject(jsonReader, type, o, l);
+ Long id = friend.getId();
+ IBot instance = MyBot.getInstance();
+ friend.setPermissions(Permissions.MEMBER);
+ if (instance.isBotOp(id)) {
+ friend.setPermissions(Permissions.ADMIN);
+ }
+ return friend;
+ }
+}
diff --git a/src/main/java/cn/wzpmc/utils/json/user/GroupUserReader.java b/src/main/java/cn/wzpmc/utils/json/user/GroupUserReader.java
new file mode 100644
index 0000000..b4bd5d2
--- /dev/null
+++ b/src/main/java/cn/wzpmc/utils/json/user/GroupUserReader.java
@@ -0,0 +1,36 @@
+package cn.wzpmc.utils.json.user;
+
+import cn.wzpmc.api.user.IBot;
+import cn.wzpmc.api.user.group.GroupUser;
+import cn.wzpmc.api.user.permission.Permissions;
+import cn.wzpmc.entities.user.bot.MyBot;
+import com.alibaba.fastjson2.JSONFactory;
+import com.alibaba.fastjson2.JSONReader;
+import com.alibaba.fastjson2.reader.ObjectReader;
+import com.alibaba.fastjson2.reader.ObjectReaderCreator;
+import com.alibaba.fastjson2.reader.ObjectReaderProvider;
+
+import java.lang.reflect.Type;
+import java.util.Objects;
+
+/**
+ * @author wzp
+ * @version 1.0.0
+ * @since 2024/8/25 15:08
+ */
+public class GroupUserReader implements ObjectReader {
+ @Override
+ public GroupUser readObject(JSONReader jsonReader, Type type, Object o, long l) {
+ ObjectReaderProvider defaultObjectReaderProvider = JSONFactory.getDefaultObjectReaderProvider();
+ ObjectReaderCreator creator = defaultObjectReaderProvider.getCreator();
+ ObjectReader objectReader = creator.createObjectReader(GroupUser.class);
+ GroupUser user = objectReader.readObject(jsonReader, type, o, l);
+ Long id = user.getId();
+ IBot instance = MyBot.getInstance();
+ user.setPermissions(Permissions.valueOf(user.getRole().name()));
+ if (Objects.nonNull(user.getPermissions()) && !user.getPermissions().isAdmin() && instance.isBotOp(id)) {
+ user.setPermissions(Permissions.ADMIN);
+ }
+ return user;
+ }
+}
diff --git a/src/test/java/TestCqUtils.java b/src/test/java/TestCqUtils.java
new file mode 100644
index 0000000..7fa15ff
--- /dev/null
+++ b/src/test/java/TestCqUtils.java
@@ -0,0 +1,29 @@
+import cn.wzpmc.api.message.json.JsonMessagePart;
+import cn.wzpmc.api.utils.CqCodeUtils;
+import org.junit.jupiter.api.Test;
+
+import java.util.Map;
+
+/**
+ * @author wzp
+ * @version 1.0.0
+ * @since 2024/8/26 14:14
+ */
+public class TestCqUtils {
+ @Test
+ public void testIsCq(){
+ System.out.println(CqCodeUtils.isCQ("[CQ:at,qq=123456789]"));
+ }
+ @Test
+ public void testCqParser(){
+ Map parse = CqCodeUtils.parse("[CQ:at,qq=123456789,name=123]");
+ for (Map.Entry stringStringEntry : parse.entrySet()) {
+ System.out.println(stringStringEntry);
+ }
+ }
+ @Test
+ public void testParseCq(){
+ JsonMessagePart jsonMessagePart = CqCodeUtils.parseToPart("[CQ:at,qq=123456789,name=123]");
+ System.out.println(jsonMessagePart);
+ }
+}