feat: adding command system
This commit is contained in:
parent
fa81e235bb
commit
932f903455
2
.idea/compiler.xml
generated
2
.idea/compiler.xml
generated
@ -10,6 +10,6 @@
|
||||
<module name="MyBot.main" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
<bytecodeTargetLevel target="11" />
|
||||
<bytecodeTargetLevel target="17" />
|
||||
</component>
|
||||
</project>
|
2
.idea/fileTemplates/includes/Version.txt
generated
2
.idea/fileTemplates/includes/Version.txt
generated
@ -1 +1 @@
|
||||
0.0.1-dev
|
||||
0.0.2-dev
|
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@ -4,7 +4,7 @@
|
||||
<component name="FrameworkDetectionExcludesConfiguration">
|
||||
<file type="web" url="file://$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="temurin-17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
@ -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<Jar>("sourcesJar") {
|
||||
archiveClassifier.set("sources")
|
||||
from(sourceSets.main.get().allSource)
|
||||
}
|
||||
tasks.withType<ShadowJar> {
|
||||
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<MavenPublication>("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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -37,7 +37,6 @@ public interface JsonMessagePart {
|
||||
.append('(')
|
||||
.append('\n');
|
||||
Map<String, String> 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);
|
||||
|
48
src/main/java/cn/wzpmc/api/plugins/BasePlugin.java
Normal file
48
src/main/java/cn/wzpmc/api/plugins/BasePlugin.java
Normal file
@ -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 <T> 插件主类类型
|
||||
*/
|
||||
static <T extends BasePlugin> T getPlugin(Class<T> 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();
|
||||
}
|
35
src/main/java/cn/wzpmc/api/plugins/IPluginClassLoader.java
Normal file
35
src/main/java/cn/wzpmc/api/plugins/IPluginClassLoader.java
Normal file
@ -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();
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
20
src/main/java/cn/wzpmc/api/user/permission/Permissions.java
Normal file
20
src/main/java/cn/wzpmc/api/user/permission/Permissions.java
Normal file
@ -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
|
||||
}
|
@ -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<CommandSender> getCommandNode() {
|
||||
return LiteralArgumentBuilder.<CommandSender>literal("stop")
|
||||
.requires(CommandSender::isAdmin)
|
||||
.executes((e) -> {
|
||||
this.bot.stop();
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
56
src/main/java/cn/wzpmc/console/MyBotConsole.java
Normal file
56
src/main/java/cn/wzpmc/console/MyBotConsole.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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<CommandSender> dispatcher = new CommandDispatcher<>();
|
||||
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;
|
||||
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<String> 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<String> tabComplete(CommandSender sender, String rawCommandLine){
|
||||
public List<String> tabComplete(CommandSender sender, String rawCommandLine, int cursor){
|
||||
CommandPart commandPart = new CommandPart(rawCommandLine);
|
||||
List<String> 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<String, RawCommand> 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<Candidate> 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<CommandSender> 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<CommandSender> 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) {
|
||||
|
||||
}
|
||||
}
|
||||
|
23
src/main/java/cn/wzpmc/plugins/JavaPlugin.java
Normal file
23
src/main/java/cn/wzpmc/plugins/JavaPlugin.java
Normal file
@ -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!!!"));
|
||||
}
|
||||
}
|
30
src/main/java/cn/wzpmc/plugins/PluginClassLoader.java
Normal file
30
src/main/java/cn/wzpmc/plugins/PluginClassLoader.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
@ -2,10 +2,10 @@
|
||||
<Configuration status="WARN" monitorInterval="30">
|
||||
<Appenders>
|
||||
<!-- 控制台输出 -->
|
||||
<Console name="Console" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%p] %c - %m%n"/>
|
||||
<TerminalConsole name="Console">
|
||||
<PatternLayout pattern="%highlight{[%d{HH:mm:ss} %level]: %msg%n%xEx}" disableAnsi="${tca:disableAnsi}"/>
|
||||
<ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
|
||||
</Console>
|
||||
</TerminalConsole>
|
||||
|
||||
<!-- 文件输出 -->
|
||||
<RollingFile name="File" fileName="./logs/latest.log"
|
||||
@ -14,7 +14,7 @@
|
||||
<Policies>
|
||||
<OnStartupTriggeringPolicy/>
|
||||
<!-- 按日期滚动日志 -->
|
||||
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
|
||||
<TimeBasedTriggeringPolicy interval="86400" modulate="true"/>
|
||||
</Policies>
|
||||
<DefaultRolloverStrategy fileIndex="max" max="7"/>
|
||||
</RollingFile>
|
||||
|
Loading…
x
Reference in New Issue
Block a user