diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index ef4060e..53eb9c3 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -10,6 +10,6 @@
-
+
\ No newline at end of file
diff --git a/.idea/fileTemplates/includes/Version.txt b/.idea/fileTemplates/includes/Version.txt
index 772a55e..e59eb1a 100644
--- a/.idea/fileTemplates/includes/Version.txt
+++ b/.idea/fileTemplates/includes/Version.txt
@@ -1 +1 @@
-0.0.1-dev
\ No newline at end of file
+0.0.2-dev
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 5d98256..f6589e3 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -4,7 +4,7 @@
-
+
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index 0d5d7ec..4c896d4 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,39 +1,62 @@
+import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
+import com.github.jengelman.gradle.plugins.shadow.transformers.Log4j2PluginsCacheFileTransformer
+
val projectName = rootProject.name
val groupName by extra("cn.wzpmc")
val projectArtifactId by extra("my-bot")
-val projectVersion by extra("0.0.1-dev")
+val projectVersion by extra("0.0.2-dev")
plugins {
id("java")
id("maven-publish")
+ id("com.github.johnrengelman.shadow") version "8.1.1"
}
group = groupName
version = projectVersion
-
repositories {
mavenCentral()
maven("https://libraries.minecraft.net")
}
dependencies {
+ implementation("net.minecrell:terminalconsoleappender:1.3.0") {
+ exclude(group = "org.apache.logging.log4j", module = "log4j-core")
+ exclude(group = "org.apache.logging.log4j", module = "log4j-api")
+ }
implementation("com.mojang:brigadier:1.0.18")
// https://mvnrepository.com/artifact/io.netty/netty-all
implementation("io.netty:netty-all:4.1.112.Final")
// https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core
implementation("org.apache.logging.log4j:log4j-core:2.23.1")
+ // https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api
+ implementation("org.apache.logging.log4j:log4j-api:2.23.1")
+ // https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-jul
+ implementation("org.apache.logging.log4j:log4j-jul:2.23.1")
// https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2
implementation("com.alibaba.fastjson2:fastjson2:2.0.52")
// https://mvnrepository.com/artifact/org.yaml/snakeyaml
implementation("org.yaml:snakeyaml:2.2")
// https://mvnrepository.com/artifact/org.jline/jline
- implementation("org.jline:jline:3.26.3")
+ implementation("org.jline:jline-terminal:3.26.3")
+ implementation("org.jline:jline-reader:3.26.3")
+ /*implementation("org.jline:jline-terminal-jni:3.26.3")
+ implementation("org.jline:jline-terminal-ffm:3.26.3")*/
+ // https://mvnrepository.com/artifact/org.jline/jline-terminal-jansi
+ implementation("org.jline:jline-terminal-jansi:3.26.3")
+ // https://mvnrepository.com/artifact/org.fusesource.jansi/jansi
+ implementation("org.fusesource.jansi:jansi:2.4.1")
+ /*// https://mvnrepository.com/artifact/org.jline/jline-terminal-jna
+ implementation("org.jline:jline-terminal-jna:3.26.3")
+ // https://mvnrepository.com/artifact/net.java.dev.jna/jna
+ implementation("net.java.dev.jna:jna:5.14.0")*/
// https://mvnrepository.com/artifact/org.projectlombok/lombok
compileOnly("org.projectlombok:lombok:1.18.34")
annotationProcessor("org.projectlombok:lombok:1.18.34")
testImplementation(platform("org.junit:junit-bom:5.10.0"))
testImplementation("org.junit.jupiter:junit-jupiter")
}
+
tasks.compileJava {
options.encoding = "UTF-8"
}
@@ -48,6 +71,21 @@ tasks.register("sourcesJar") {
archiveClassifier.set("sources")
from(sourceSets.main.get().allSource)
}
+tasks.withType {
+ manifest {
+ attributes(
+ "Main-Class" to "cn.wzpmc.Main"
+ )
+ }
+
+ archiveBaseName.set("MyBot")
+ archiveVersion.set(projectVersion)
+ archiveClassifier.set("")
+ transform(Log4j2PluginsCacheFileTransformer::class.java)
+}
+tasks.named("build") {
+ dependsOn(tasks.named("shadowJar"))
+}
publishing {
publications {
create("mavenJava") {
@@ -88,15 +126,14 @@ publishing {
repositories {
maven {
- val releasesRepoUrl = uri("http://server.wzpmc.cn:8081/repository/maven-releases")
- val snapshotsRepoUrl = uri("http://server.wzpmc.cn:8081/repository/maven-snapshots")
+ val releasesRepoUrl = uri("https://wzpmc.cn:90/repository/maven-releases")
+ val snapshotsRepoUrl = uri("https://wzpmc.cn:90/repository/maven-snapshots")
url = if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl
credentials {
username = project.findProperty("repo.user") as String? ?: ""
password = project.findProperty("repo.password") as String? ?: ""
}
- isAllowInsecureProtocol = true
}
}
}
diff --git a/src/main/java/cn/wzpmc/Main.java b/src/main/java/cn/wzpmc/Main.java
index e1ebe9f..28d8bff 100644
--- a/src/main/java/cn/wzpmc/Main.java
+++ b/src/main/java/cn/wzpmc/Main.java
@@ -1,10 +1,13 @@
package cn.wzpmc;
+import cn.wzpmc.commands.StopCommand;
import cn.wzpmc.configuration.Configuration;
+import cn.wzpmc.console.MyBotConsole;
+import cn.wzpmc.entities.user.bot.MyBot;
import cn.wzpmc.network.WebSocketConnectionHandler;
+import cn.wzpmc.plugins.CommandManager;
import cn.wzpmc.utils.TemplateFileUtils;
import cn.wzpmc.utils.YamlUtils;
-import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
@@ -18,6 +21,8 @@ public class Main {
private static final String DEFAULT_CONFIGURATION_FILE_PATH = "templates/config.yaml";
@SneakyThrows
public static void main(String[] args) {
+ System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager");
+ System.setProperty("terminal.jline", "true");
log.info("启动MyBot...");
File configurationFile = new File("config.yaml");
if (TemplateFileUtils.saveDefaultConfig(Main.class.getClassLoader(), DEFAULT_CONFIGURATION_FILE_PATH, configurationFile)) {
@@ -36,7 +41,10 @@ public class Main {
}
WebSocketConnectionHandler webSocketConnectionHandler = new WebSocketConnectionHandler();
ChannelFuture future = webSocketConnectionHandler.connect(uri);
- Channel channel = future.sync().channel();
-
+ MyBot myBot = new MyBot(configuration);
+ CommandManager commandManager = myBot.getCommandManager();
+ commandManager.registerCommand(new StopCommand(myBot));
+ MyBotConsole myBotConsole = new MyBotConsole(myBot, webSocketConnectionHandler);
+ myBotConsole.start();
}
}
\ No newline at end of file
diff --git a/src/main/java/cn/wzpmc/api/message/json/JsonMessagePart.java b/src/main/java/cn/wzpmc/api/message/json/JsonMessagePart.java
index 8e545e6..27bbdef 100644
--- a/src/main/java/cn/wzpmc/api/message/json/JsonMessagePart.java
+++ b/src/main/java/cn/wzpmc/api/message/json/JsonMessagePart.java
@@ -37,7 +37,6 @@ public interface JsonMessagePart {
.append('(')
.append('\n');
Map data = this.getData();
- int i = 0;
data.forEach((key, value) -> stringBuilder.append('\t').append(key).append('=').append(value).append(',').append('\n'));
int length = stringBuilder.length();
stringBuilder.delete(length - 2, length - 1);
diff --git a/src/main/java/cn/wzpmc/api/plugins/BasePlugin.java b/src/main/java/cn/wzpmc/api/plugins/BasePlugin.java
new file mode 100644
index 0000000..7d572ce
--- /dev/null
+++ b/src/main/java/cn/wzpmc/api/plugins/BasePlugin.java
@@ -0,0 +1,48 @@
+package cn.wzpmc.api.plugins;
+
+import cn.wzpmc.api.user.IBot;
+
+/**
+ * 插件基类
+ * @author wzp
+ * @version 0.0.2-dev
+ * @since 2024/7/31 下午6:02
+ */
+public interface BasePlugin {
+ /**
+ * 获取插件主类
+ * @author wzp
+ * @since 2024/7/31 下午7:07 v0.0.2-dev
+ * @param pluginClass 插件主类类名
+ * @return 插件主类
+ * @param 插件主类类型
+ */
+ static T getPlugin(Class pluginClass){
+ ClassLoader loader = pluginClass.getClassLoader();
+ if (loader instanceof IPluginClassLoader){
+ BasePlugin plugin = ((IPluginClassLoader) loader).getPlugin();
+ if (pluginClass.isInstance(plugin)) {
+ return pluginClass.cast(plugin);
+ }
+ }
+ throw new RuntimeException(new IllegalAccessException("You shouldn't load plugin class without PluginClassLoader!!!"));
+ }
+ /**
+ * 获取Bot
+ * @author wzp
+ * @since 2024/7/31 下午7:06 v0.0.2-dev
+ * @return Bot对象
+ */
+ default IBot getBot() {
+ IPluginClassLoader classLoader = this.getClassLoader();
+ return classLoader.getBot();
+ }
+
+ /**
+ * 获取插件所使用的类加载器
+ * @author wzp
+ * @since 2024/7/31 下午7:11 v0.0.2-dev
+ * @return 类加载器
+ */
+ IPluginClassLoader getClassLoader();
+}
diff --git a/src/main/java/cn/wzpmc/api/plugins/IPluginClassLoader.java b/src/main/java/cn/wzpmc/api/plugins/IPluginClassLoader.java
new file mode 100644
index 0000000..1a72633
--- /dev/null
+++ b/src/main/java/cn/wzpmc/api/plugins/IPluginClassLoader.java
@@ -0,0 +1,35 @@
+package cn.wzpmc.api.plugins;
+
+import cn.wzpmc.api.user.IBot;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+
+/**
+ * 插件类加载器
+ * @author wzp
+ * @version 0.0.2-dev
+ * @since 2024/7/31 下午6:59
+ */
+public abstract class IPluginClassLoader extends URLClassLoader {
+
+ public IPluginClassLoader(URL[] urls) {
+ super(urls);
+ }
+
+ /**
+ * 获取当前插件
+ * @author wzp
+ * @since 2024/7/31 下午7:15 v0.0.2-dev
+ * @return 插件
+ */
+ abstract public BasePlugin getPlugin();
+
+ /**
+ * 获取Bot
+ * @author wzp
+ * @since 2024/7/31 下午7:15 v0.0.2-dev
+ * @return Bot对象
+ */
+ abstract public IBot getBot();
+}
diff --git a/src/main/java/cn/wzpmc/api/user/CommandSender.java b/src/main/java/cn/wzpmc/api/user/CommandSender.java
index c8ea646..e0fb377 100644
--- a/src/main/java/cn/wzpmc/api/user/CommandSender.java
+++ b/src/main/java/cn/wzpmc/api/user/CommandSender.java
@@ -1,6 +1,7 @@
package cn.wzpmc.api.user;
import cn.wzpmc.api.message.MessageComponent;
+import cn.wzpmc.api.user.permission.Permissions;
/**
* 消息发送者
@@ -31,4 +32,22 @@ public interface CommandSender {
* @param messageComponent 消息组件
*/
void sendMessage(MessageComponent messageComponent);
+
+ /**
+ * 获取指令发送者的权限
+ * @author wzp
+ * @since 2024/8/1 下午4:50 v0.0.2-dev
+ * @return 权限
+ */
+ Permissions getPermission();
+
+ /**
+ * 指令发送者是否为管理员
+ * @author wzp
+ * @since 2024/8/1 下午4:50 v0.0.2-dev
+ * @return 是否为管理员
+ */
+ default boolean isAdmin(){
+ return Permissions.ADMIN.equals(this.getPermission());
+ }
}
diff --git a/src/main/java/cn/wzpmc/api/user/IBot.java b/src/main/java/cn/wzpmc/api/user/IBot.java
index 06a78ab..8406e3e 100644
--- a/src/main/java/cn/wzpmc/api/user/IBot.java
+++ b/src/main/java/cn/wzpmc/api/user/IBot.java
@@ -25,4 +25,11 @@ public interface IBot extends CommandSender {
* @return 指令管理器
*/
ICommandManager getCommandManager();
+
+ /**
+ * 停止Bot运行
+ * @author wzp
+ * @since 2024/8/1 下午4:57 v0.0.2-dev
+ */
+ void stop();
}
diff --git a/src/main/java/cn/wzpmc/api/user/permission/Permissions.java b/src/main/java/cn/wzpmc/api/user/permission/Permissions.java
new file mode 100644
index 0000000..189b867
--- /dev/null
+++ b/src/main/java/cn/wzpmc/api/user/permission/Permissions.java
@@ -0,0 +1,20 @@
+package cn.wzpmc.api.user.permission;
+
+/**
+ * 权限
+ * @author wzp
+ * @version 0.0.2-dev
+ * @since 2024/8/1 下午4:48
+ */
+public enum Permissions {
+ /**
+ * 普通用户
+ * @since 2024/8/1 下午4:49 v0.0.2-dev
+ */
+ USER,
+ /**
+ * 管理员
+ * @since 2024/8/1 下午4:49 v0.0.2-dev
+ */
+ ADMIN
+}
diff --git a/src/main/java/cn/wzpmc/commands/StopCommand.java b/src/main/java/cn/wzpmc/commands/StopCommand.java
index 75460b9..1ea2f84 100644
--- a/src/main/java/cn/wzpmc/commands/StopCommand.java
+++ b/src/main/java/cn/wzpmc/commands/StopCommand.java
@@ -1,9 +1,27 @@
package cn.wzpmc.commands;
+import cn.wzpmc.api.commands.BrigadierCommand;
+import cn.wzpmc.api.user.CommandSender;
+import cn.wzpmc.api.user.IBot;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import lombok.RequiredArgsConstructor;
+
/**
+ * /stop指令
* @author wzp
* @version 0.0.1-dev
* @since 2024/7/31 上午2:26
*/
-public class StopCommand {
+@RequiredArgsConstructor
+public class StopCommand implements BrigadierCommand {
+ private final IBot bot;
+ @Override
+ public LiteralArgumentBuilder getCommandNode() {
+ return LiteralArgumentBuilder.literal("stop")
+ .requires(CommandSender::isAdmin)
+ .executes((e) -> {
+ this.bot.stop();
+ return 0;
+ });
+ }
}
diff --git a/src/main/java/cn/wzpmc/console/MyBotConsole.java b/src/main/java/cn/wzpmc/console/MyBotConsole.java
new file mode 100644
index 0000000..fe5bf19
--- /dev/null
+++ b/src/main/java/cn/wzpmc/console/MyBotConsole.java
@@ -0,0 +1,56 @@
+package cn.wzpmc.console;
+
+import cn.wzpmc.entities.user.bot.MyBot;
+import cn.wzpmc.network.WebSocketConnectionHandler;
+import cn.wzpmc.plugins.CommandManager;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+import net.minecrell.terminalconsole.SimpleTerminalConsole;
+import org.jline.reader.LineReader;
+import org.jline.reader.LineReaderBuilder;
+
+/**
+ * 主控制台
+ * @author wzp
+ * @version 0.0.2-dev
+ * @since 2024/7/31 下午9:47
+ */
+@Log4j2
+@RequiredArgsConstructor
+public class MyBotConsole extends SimpleTerminalConsole {
+ @Getter
+ private boolean running = true;
+ private final MyBot bot;
+ private final CommandManager commandManager;
+ private final WebSocketConnectionHandler webSocketConnectionHandler;
+ public MyBotConsole(MyBot bot, WebSocketConnectionHandler webSocketConnectionHandler){
+ this.bot = bot;
+ this.commandManager = bot.getCommandManager();
+ this.webSocketConnectionHandler = webSocketConnectionHandler;
+ }
+
+ @Override
+ protected LineReader buildReader(LineReaderBuilder builder) {
+ return super.buildReader(builder.appName("MyBot").completer(commandManager).highlighter(commandManager));
+ }
+
+ @Override
+ protected void runCommand(String command) {
+ if (!commandManager.execute(this.bot, command)) {
+ log.warn("执行指令:`{}`失败!", command);
+ }
+ }
+
+ @Override
+ public void shutdown() {
+ running = false;
+ this.webSocketConnectionHandler.kill();
+ }
+
+ @Override
+ public void start() {
+ this.bot.setConsole(this);
+ super.start();
+ }
+}
\ No newline at end of file
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 be1ff85..fb6610b 100644
--- a/src/main/java/cn/wzpmc/entities/user/bot/MyBot.java
+++ b/src/main/java/cn/wzpmc/entities/user/bot/MyBot.java
@@ -4,10 +4,13 @@ import cn.wzpmc.api.message.MessageComponent;
import cn.wzpmc.api.message.StringMessage;
import cn.wzpmc.api.message.json.JsonMessage;
import cn.wzpmc.api.user.IBot;
+import cn.wzpmc.api.user.permission.Permissions;
import cn.wzpmc.configuration.Configuration;
+import cn.wzpmc.console.MyBotConsole;
import cn.wzpmc.plugins.CommandManager;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
+import lombok.Setter;
import lombok.extern.log4j.Log4j2;
/**
@@ -21,9 +24,13 @@ import lombok.extern.log4j.Log4j2;
@Getter
public class MyBot implements IBot {
private final Configuration configuration;
- private final Long id;
- private final Long name;
- private final CommandManager commandManager = new CommandManager();
+ @Setter
+ private Long id;
+ @Setter
+ private Long name;
+ private final CommandManager commandManager = new CommandManager(this);
+ @Setter
+ private MyBotConsole console = null;
@Override
public void sendMessage(MessageComponent messageComponent) {
@@ -34,4 +41,16 @@ public class MyBot implements IBot {
log.info(((JsonMessage) messageComponent).toTextDisplay());
}
}
+
+ @Override
+ public Permissions getPermission() {
+ return Permissions.ADMIN;
+ }
+
+ @Override
+ public void stop() {
+ if (this.console != null) {
+ this.console.shutdown();
+ }
+ }
}
diff --git a/src/main/java/cn/wzpmc/network/WebSocketConnectionHandler.java b/src/main/java/cn/wzpmc/network/WebSocketConnectionHandler.java
index 094b30e..fa80657 100644
--- a/src/main/java/cn/wzpmc/network/WebSocketConnectionHandler.java
+++ b/src/main/java/cn/wzpmc/network/WebSocketConnectionHandler.java
@@ -27,6 +27,7 @@ public class WebSocketConnectionHandler {
* @author wzp
* @since 2024/7/30 下午11:55 v0.0.1-dev
* @param websocket websocket连接地址
+ * @return 一个ChannelFuture对象
*/
public ChannelFuture connect(URI websocket){
log.info("正在连接websocket");
@@ -44,6 +45,7 @@ public class WebSocketConnectionHandler {
* @since 2024/7/31 上午2:04 v0.0.1-dev
*/
public void kill(){
+ log.info("结束连接...");
this.eventLoopGroup.shutdownGracefully();
}
}
diff --git a/src/main/java/cn/wzpmc/plugins/CommandManager.java b/src/main/java/cn/wzpmc/plugins/CommandManager.java
index a27f0f8..ced14cc 100644
--- a/src/main/java/cn/wzpmc/plugins/CommandManager.java
+++ b/src/main/java/cn/wzpmc/plugins/CommandManager.java
@@ -2,21 +2,31 @@ package cn.wzpmc.plugins;
import cn.wzpmc.api.commands.BrigadierCommand;
import cn.wzpmc.api.commands.RawCommand;
+import cn.wzpmc.api.message.StringMessage;
import cn.wzpmc.api.plugins.ICommandManager;
import cn.wzpmc.api.user.CommandSender;
+import cn.wzpmc.api.user.IBot;
import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.ParseResults;
+import com.mojang.brigadier.context.ParsedCommandNode;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.Suggestion;
import com.mojang.brigadier.suggestion.Suggestions;
-import lombok.NoArgsConstructor;
+import com.mojang.brigadier.tree.LiteralCommandNode;
import lombok.SneakyThrows;
+import lombok.ToString;
import lombok.extern.log4j.Log4j2;
+import org.jline.reader.*;
+import org.jline.utils.AttributedString;
+import org.jline.utils.AttributedStringBuilder;
+import org.jline.utils.AttributedStyle;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.stream.Collectors;
+import java.util.regex.Pattern;
/**
* 指令管理器实现类
@@ -25,10 +35,14 @@ import java.util.stream.Collectors;
* @since 2024/7/31 上午3:13
*/
@Log4j2
-@NoArgsConstructor
-public class CommandManager implements ICommandManager {
+public class CommandManager implements ICommandManager, Completer, Highlighter {
private final CommandDispatcher dispatcher = new CommandDispatcher<>();
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;
+ public CommandManager(IBot bot) {
+ this.bot = bot;
+ }
@Override
public void registerCommand(RawCommand rawCommand, String name) {
if (rawCommands.containsKey(name)){
@@ -41,6 +55,7 @@ public class CommandManager implements ICommandManager {
public void registerCommand(BrigadierCommand brigadierCommand){
dispatcher.register(brigadierCommand.getCommandNode());
}
+ @ToString
private static final class CommandPart {
private final String name;
private final List args;
@@ -67,6 +82,11 @@ public class CommandManager implements ICommandManager {
try {
dispatcher.execute(rawCommandLine, sender);
} catch (CommandSyntaxException e) {
+ if (e.getType().equals(CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownCommand())) {
+ sender.sendMessage(StringMessage.text(this.bot.getConfiguration().getFallback().getCommand()));
+ return false;
+ }
+ sender.sendMessage(StringMessage.text(e.getLocalizedMessage()));
return false;
}
}
@@ -79,17 +99,83 @@ public class CommandManager implements ICommandManager {
* @since 2024/7/31 上午3:36 v0.0.1-dev
* @param sender 消息发送者
* @param rawCommandLine 完整命令行
+ * @param cursor 当前光标位置
* @return 所有被补全的指令
*/
@SneakyThrows
- public List tabComplete(CommandSender sender, String rawCommandLine){
+ public List tabComplete(CommandSender sender, String rawCommandLine, int cursor){
CommandPart commandPart = new CommandPart(rawCommandLine);
List result = new ArrayList<>();
if (rawCommands.containsKey(commandPart.name)) {
result.addAll(rawCommands.get(commandPart.name).onTabComplete(sender, commandPart.args));
}
- Suggestions suggestions = dispatcher.getCompletionSuggestions(dispatcher.parse(rawCommandLine, sender)).get();
- result.addAll(suggestions.getList().stream().map(Suggestion::getText).collect(Collectors.toList()));
+ for (Map.Entry stringRawCommandEntry : rawCommands.entrySet()) {
+ String key = stringRawCommandEntry.getKey();
+ if (key.contains(commandPart.name)){
+ result.add(key);
+ }
+ }
+ Suggestions suggestions = dispatcher.getCompletionSuggestions(dispatcher.parse(rawCommandLine, sender), cursor).get();
+ result.addAll(suggestions.getList().stream().map(Suggestion::getText).toList());
return result;
}
+
+ @Override
+ public void complete(LineReader lineReader, ParsedLine parsedLine, List list) {
+ String line = parsedLine.line();
+ int cursor = parsedLine.cursor();
+ list.addAll(this.tabComplete(this.bot, line, cursor).stream().map(Candidate::new).toList());
+ }
+
+ @Override
+ public AttributedString highlight(LineReader lineReader, String s) {
+ final AttributedStringBuilder builder = new AttributedStringBuilder();
+ String[] strings = s.split(" ");
+ String commandName = strings[0];
+ if (rawCommands.containsKey(commandName)){
+ builder.append(commandName, AttributedStyle.DEFAULT.foreground(AttributedStyle.GREEN)).append(' ');
+ for (int i = 1; i < strings.length; i++) {
+ builder.append(strings[i]).append(' ');
+ }
+ }else {
+ final ParseResults results = this.dispatcher.parse(s, this.bot);
+ int pos = 0;
+ if (s.startsWith("/")) {
+ builder.append("/", AttributedStyle.DEFAULT);
+ pos = 1;
+ }
+ int component = -1;
+ for (final ParsedCommandNode node : results.getContext().getLastChild().getNodes()) {
+ if (node.getRange().getStart() >= s.length()) {
+ break;
+ }
+ final int start = node.getRange().getStart();
+ final int end = Math.min(node.getRange().getEnd(), s.length());
+ builder.append(s.substring(pos, start), AttributedStyle.DEFAULT);
+ if (node.getNode() instanceof LiteralCommandNode) {
+ builder.append(s.substring(start, end), AttributedStyle.DEFAULT);
+ } else {
+ if (++component >= COLORS.length) {
+ component = 0;
+ }
+ builder.append(s.substring(start, end), AttributedStyle.DEFAULT.foreground(COLORS[component]));
+ }
+ pos = end;
+ }
+ if (pos < s.length()) {
+ builder.append((s.substring(pos)), AttributedStyle.DEFAULT.foreground(AttributedStyle.RED));
+ }
+ }
+ return builder.toAttributedString();
+ }
+
+ @Override
+ public void setErrorPattern(Pattern pattern) {
+
+ }
+
+ @Override
+ public void setErrorIndex(int i) {
+
+ }
}
diff --git a/src/main/java/cn/wzpmc/plugins/JavaPlugin.java b/src/main/java/cn/wzpmc/plugins/JavaPlugin.java
new file mode 100644
index 0000000..b4eb1c6
--- /dev/null
+++ b/src/main/java/cn/wzpmc/plugins/JavaPlugin.java
@@ -0,0 +1,23 @@
+package cn.wzpmc.plugins;
+
+import cn.wzpmc.api.plugins.BasePlugin;
+import cn.wzpmc.api.plugins.IPluginClassLoader;
+
+/**
+ * Java插件基类
+ * @author wzp
+ * @version 0.0.2-dev
+ * @since 2024/7/31 下午7:01
+ */
+public class JavaPlugin implements BasePlugin {
+
+ @Override
+ public IPluginClassLoader getClassLoader() {
+ Class extends JavaPlugin> aClass = this.getClass();
+ ClassLoader loader = aClass.getClassLoader();
+ if (loader instanceof IPluginClassLoader){
+ return (IPluginClassLoader) loader;
+ }
+ throw new RuntimeException(new IllegalAccessException("You shouldn't load plugin class without PluginClassLoader!!!"));
+ }
+}
diff --git a/src/main/java/cn/wzpmc/plugins/PluginClassLoader.java b/src/main/java/cn/wzpmc/plugins/PluginClassLoader.java
new file mode 100644
index 0000000..528faec
--- /dev/null
+++ b/src/main/java/cn/wzpmc/plugins/PluginClassLoader.java
@@ -0,0 +1,30 @@
+package cn.wzpmc.plugins;
+
+import cn.wzpmc.api.plugins.BasePlugin;
+import cn.wzpmc.api.plugins.IPluginClassLoader;
+import cn.wzpmc.api.user.IBot;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+import java.net.URL;
+
+/**
+ * 插件类加载器实现
+ * @author wzp
+ * @version 0.0.2-dev
+ * @since 2024/7/31 下午7:12
+ */
+@Getter
+@EqualsAndHashCode(callSuper = true)
+@ToString
+public class PluginClassLoader extends IPluginClassLoader {
+ private final IBot bot;
+ @Setter
+ private BasePlugin plugin;
+ public PluginClassLoader(URL[] urls, IBot bot) {
+ super(urls);
+ this.bot = bot;
+ }
+}
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
index 6b18dc3..8bbd7e0 100644
--- a/src/main/resources/log4j2.xml
+++ b/src/main/resources/log4j2.xml
@@ -2,10 +2,10 @@
-
-
+
+
-
+
-
+
@@ -27,4 +27,4 @@
-
+
\ No newline at end of file