feat: adding some feature
This commit is contained in:
parent
8e5a552ab8
commit
64686d2f47
2
.idea/fileTemplates/includes/Version.txt
generated
2
.idea/fileTemplates/includes/Version.txt
generated
@ -1 +1 @@
|
||||
1.0.0
|
||||
1.0.2
|
10
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
10
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@ -0,0 +1,10 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="DuplicatedCode" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<Languages>
|
||||
<language minSize="58" name="Java" />
|
||||
</Languages>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
@ -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")
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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<JsonMessagePart> {
|
||||
@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);
|
||||
}
|
||||
}
|
@ -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<Long> {
|
||||
@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"));
|
||||
}
|
||||
}
|
55
src/main/java/cn/wzpmc/api/entities/Ops.java
Normal file
55
src/main/java/cn/wzpmc/api/entities/Ops.java
Normal file
@ -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<Long> admins = new HashSet<>();
|
||||
/**
|
||||
* 群内管理员
|
||||
* @since 2024/8/25 20:17 v1.0.0
|
||||
*/
|
||||
private final Map<String, List<Long>> 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<Long> 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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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<JsonMessagePart> 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);
|
||||
}
|
||||
}
|
||||
|
148
src/main/java/cn/wzpmc/api/utils/CqCodeUtils.java
Normal file
148
src/main/java/cn/wzpmc/api/utils/CqCodeUtils.java
Normal file
@ -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<String, String> parse(String word){
|
||||
StringBuilder key = new StringBuilder();
|
||||
boolean keyDone = false;
|
||||
StringBuilder value = new StringBuilder();
|
||||
Map<String, String> 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<String, String> 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;
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ import java.util.List;
|
||||
* @version 0.0.4-dev
|
||||
* @since 2024/8/16 00:02
|
||||
*/
|
||||
public class IncreasbleHashMap<K, V> extends HashMap<K, List<V>> implements IncreasbleMap<K, V>{
|
||||
public class IncreasbleHashMap<K, V> extends HashMap<K, List<V>> implements IncreasbleMap<K, V, List<V>>{
|
||||
@Override
|
||||
public void add(K key, V value) {
|
||||
List<V> newArrayList = super.getOrDefault(key, new ArrayList<>());
|
||||
@ -41,7 +41,7 @@ public class IncreasbleHashMap<K, V> extends HashMap<K, List<V>> implements Incr
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAll(IncreasbleMap<K, V> increasbleMap) {
|
||||
public void addAll(IncreasbleMap<K, V, List<V>> increasbleMap) {
|
||||
for (Entry<K, List<V>> entry : increasbleMap.entrySet()) {
|
||||
this.addAll(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
@ -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 <C> 集合类型
|
||||
* @param <K> key类型
|
||||
* @param <V> value类型
|
||||
*/
|
||||
public interface IncreasbleMap<K, V> extends Map<K, List<V>> {
|
||||
public interface IncreasbleMap<K, V, C extends Collection<V>> extends Map<K, C> {
|
||||
/**
|
||||
* 向一个Key中添加元素
|
||||
* @author wzp
|
||||
@ -45,7 +47,7 @@ public interface IncreasbleMap<K, V> extends Map<K, List<V>> {
|
||||
* @since 2024/8/16 00:35 v0.0.4-dev
|
||||
* @param increasbleMap 另一个表
|
||||
*/
|
||||
void addAll(IncreasbleMap<K, V> increasbleMap);
|
||||
void addAll(IncreasbleMap<K, V, C> increasbleMap);
|
||||
|
||||
/**
|
||||
* 将所有value添加到此key中
|
||||
|
77
src/main/java/cn/wzpmc/builtin/commands/DeOpCommand.java
Normal file
77
src/main/java/cn/wzpmc/builtin/commands/DeOpCommand.java
Normal file
@ -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<CommandSender> getCommandNode() {
|
||||
return LiteralArgumentBuilder.
|
||||
<CommandSender>literal("deop").
|
||||
requires(CommandSender::isAdmin).
|
||||
then(RequiredArgumentBuilder.<CommandSender, Long>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.<CommandSender>literal("group")
|
||||
.then(RequiredArgumentBuilder.<CommandSender, Long>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;
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
58
src/main/java/cn/wzpmc/builtin/commands/HelpCommand.java
Normal file
58
src/main/java/cn/wzpmc/builtin/commands/HelpCommand.java
Normal file
@ -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<CommandSender> getCommandNode() {
|
||||
return LiteralArgumentBuilder.<CommandSender>literal("help").executes(e -> {
|
||||
IBot instance = MyBot.getInstance();
|
||||
CommandManager commandManager = (CommandManager) instance.getCommandManager();
|
||||
CommandDispatcher<CommandSender> dispatcher = commandManager.getDispatcher();
|
||||
RootCommandNode<CommandSender> root = dispatcher.getRoot();
|
||||
Collection<CommandNode<CommandSender>> children = root.getChildren();
|
||||
CommandSender source = e.getSource();
|
||||
for (CommandNode<CommandSender> 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<String, RawCommand> rawCommands = commandManager.getRawCommands();
|
||||
for (Map.Entry<String, RawCommand> stringRawCommandEntry : rawCommands.entrySet()) {
|
||||
source.sendMessage(StringMessage.text("/" + stringRawCommandEntry.getKey()));
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
private static void handlerNode(Collection<CommandNode<CommandSender>> node, int tabCount, StringBuilder builder){
|
||||
for (CommandNode<CommandSender> commandSenderCommandNode : node) {
|
||||
builder.append("\t".repeat(Math.max(0, tabCount)));
|
||||
builder.append(commandSenderCommandNode.getUsageText());
|
||||
builder.append('\n');
|
||||
handlerNode(commandSenderCommandNode.getChildren(), tabCount + 1, builder);
|
||||
}
|
||||
}
|
||||
}
|
183
src/main/java/cn/wzpmc/builtin/commands/OpCommand.java
Normal file
183
src/main/java/cn/wzpmc/builtin/commands/OpCommand.java
Normal file
@ -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<CommandSender> getCommandNode() {
|
||||
return LiteralArgumentBuilder.
|
||||
<CommandSender>literal("op").
|
||||
then(LiteralArgumentBuilder.<CommandSender>literal("list").executes(e -> {
|
||||
Ops ops = instance.getOps();
|
||||
Map<String, List<Long>> groupAdmins = ops.getGroupAdmins();
|
||||
Set<Long> fullAdmins = ops.getAdmins();
|
||||
CommandSender source = e.getSource();
|
||||
Long id = source.getId();
|
||||
boolean groupAdmin = false;
|
||||
boolean fullAdmin = fullAdmins.contains(id);
|
||||
Long sendGroupId = -1L;
|
||||
List<Long> sendGroupAdmins = new ArrayList<>();
|
||||
if (source instanceof GroupCommandSender) {
|
||||
sendGroupId = ((GroupCommandSender) source).getGroupId();
|
||||
List<Long> 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<String, List<Long>> 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.<CommandSender>literal("group").
|
||||
then(RequiredArgumentBuilder.<CommandSender, Long>argument("groupId", LongArgumentType.longArg()).
|
||||
executes(e -> {
|
||||
Long groupId = e.getArgument("groupId", Long.class);
|
||||
Ops ops = instance.getOps();
|
||||
Map<String, List<Long>> groupsAdmins = ops.getGroupAdmins();
|
||||
Set<Long> admins = ops.getAdmins();
|
||||
List<Long> 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<String, List<Long>> groupsAdmins = ops.getGroupAdmins();
|
||||
Set<Long> admins = ops.getAdmins();
|
||||
List<Long> 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.<CommandSender>literal("full").executes(e -> {
|
||||
Ops ops = instance.getOps();
|
||||
Set<Long> 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.<CommandSender, Long>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.<CommandSender>literal("group")
|
||||
.then(RequiredArgumentBuilder.<CommandSender, Long>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<Long> admins){
|
||||
return "总管理:" + '\n' +
|
||||
getOpListString(admins);
|
||||
}
|
||||
private static String getGroupOpListString(Collection<Long> admins, Long groupId){
|
||||
return "群" + groupId + "的管理员:" + '\n' +
|
||||
getOpListString(admins);
|
||||
}
|
||||
private static StringBuilder getOpListString(Collection<Long> 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;
|
||||
}
|
||||
}
|
@ -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<CommandSender> getCommandNode() {
|
||||
return LiteralArgumentBuilder.<CommandSender>literal("stop")
|
||||
.requires(CommandSender::isAdmin)
|
||||
.requires(e -> {
|
||||
Ops ops = bot.getOps();
|
||||
Set<Long> 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;
|
||||
});
|
||||
}
|
@ -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("/", ""));
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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<Long> admins = this.ops.getAdmins();
|
||||
admins.add(userId);
|
||||
this.flushOpsFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOp(Long groupId, Long userId) {
|
||||
Map<String, List<Long>> admins = this.ops.getGroupAdmins();
|
||||
String string = groupId.toString();
|
||||
List<Long> 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<Long> 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<String, List<Long>> admins = this.ops.getGroupAdmins();
|
||||
String string = groupId.toString();
|
||||
if (groupAdmin && !admin) {
|
||||
List<Long> longs = admins.get(string);
|
||||
longs.remove(userId);
|
||||
admins.put(string, longs);
|
||||
} else {
|
||||
ActionResponse<List<GroupInformation>> listActionResponse = this.mainApi.doApiCall(new GetGroupListAction());
|
||||
List<GroupInformation> 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<Long> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ public class PacketHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame webSocketFrame) {
|
||||
String text = webSocketFrame.text();
|
||||
System.out.println(text);
|
||||
// System.out.println(text);
|
||||
if (!JSON.isValidObject(text)){
|
||||
log.warn("收到了无法处理的WebSocket数据包:{}", text);
|
||||
return;
|
||||
@ -59,7 +59,8 @@ public class PacketHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
try {
|
||||
this.bot.triggerEvent(event);
|
||||
} catch (InvocationTargetException | IllegalAccessException e) {
|
||||
log.error(new RuntimeException(e));
|
||||
log.throwing(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.suggestion.Suggestion;
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.ToString;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
@ -37,7 +38,9 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
@Log4j2
|
||||
public class CommandManager implements ICommandManager, Completer, Highlighter {
|
||||
@Getter
|
||||
private final CommandDispatcher<CommandSender> dispatcher = new CommandDispatcher<>();
|
||||
@Getter
|
||||
private final ConcurrentHashMap<String, RawCommand> rawCommands = new ConcurrentHashMap<>();
|
||||
private static final int[] COLORS = {AttributedStyle.CYAN, AttributedStyle.YELLOW, AttributedStyle.GREEN, AttributedStyle.MAGENTA, AttributedStyle.BLUE};
|
||||
private final IBot bot;
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<Class<? extends Event>, EventHandlerMethod> loadEvents(Object eventHandlerObject){
|
||||
public static IncreasbleMap<Class<? extends Event>, EventHandlerMethod, List<EventHandlerMethod>> loadEvents(Object eventHandlerObject){
|
||||
Class<?> eventHandlerClass = eventHandlerObject.getClass();
|
||||
IncreasbleMap<Class<? extends Event>, EventHandlerMethod> result = new IncreasbleHashMap<>();
|
||||
IncreasbleMap<Class<? extends Event>, EventHandlerMethod, List<EventHandlerMethod>> result = new IncreasbleHashMap<>();
|
||||
for (Method declaredMethod : eventHandlerClass.getDeclaredMethods()) {
|
||||
declaredMethod.setAccessible(true);
|
||||
if (!declaredMethod.isAnnotationPresent(EventHandler.class)){
|
||||
|
@ -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<JsonMessage> {
|
||||
JSONArray objects = jsonReader.readJSONArray();
|
||||
JsonMessage message = new JsonMessage();
|
||||
List<JsonMessagePart> 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;
|
||||
}
|
||||
|
35
src/main/java/cn/wzpmc/utils/json/user/FriendUserReader.java
Normal file
35
src/main/java/cn/wzpmc/utils/json/user/FriendUserReader.java
Normal file
@ -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<Friend> {
|
||||
@Override
|
||||
public Friend readObject(JSONReader jsonReader, Type type, Object o, long l) {
|
||||
ObjectReaderProvider defaultObjectReaderProvider = JSONFactory.getDefaultObjectReaderProvider();
|
||||
ObjectReaderCreator creator = defaultObjectReaderProvider.getCreator();
|
||||
ObjectReader<Friend> 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;
|
||||
}
|
||||
}
|
36
src/main/java/cn/wzpmc/utils/json/user/GroupUserReader.java
Normal file
36
src/main/java/cn/wzpmc/utils/json/user/GroupUserReader.java
Normal file
@ -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<GroupUser> {
|
||||
@Override
|
||||
public GroupUser readObject(JSONReader jsonReader, Type type, Object o, long l) {
|
||||
ObjectReaderProvider defaultObjectReaderProvider = JSONFactory.getDefaultObjectReaderProvider();
|
||||
ObjectReaderCreator creator = defaultObjectReaderProvider.getCreator();
|
||||
ObjectReader<GroupUser> 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;
|
||||
}
|
||||
}
|
29
src/test/java/TestCqUtils.java
Normal file
29
src/test/java/TestCqUtils.java
Normal file
@ -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<String, String> parse = CqCodeUtils.parse("[CQ:at,qq=123456789,name=123]");
|
||||
for (Map.Entry<String, String> 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);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user