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" />
|
<module name="MyBot.main" />
|
||||||
</profile>
|
</profile>
|
||||||
</annotationProcessing>
|
</annotationProcessing>
|
||||||
<bytecodeTargetLevel target="11" />
|
<bytecodeTargetLevel target="17" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</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">
|
<component name="FrameworkDetectionExcludesConfiguration">
|
||||||
<file type="web" url="file://$PROJECT_DIR$" />
|
<file type="web" url="file://$PROJECT_DIR$" />
|
||||||
</component>
|
</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" />
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</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 projectName = rootProject.name
|
||||||
val groupName by extra("cn.wzpmc")
|
val groupName by extra("cn.wzpmc")
|
||||||
val projectArtifactId by extra("my-bot")
|
val projectArtifactId by extra("my-bot")
|
||||||
val projectVersion by extra("0.0.1-dev")
|
val projectVersion by extra("0.0.2-dev")
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("java")
|
id("java")
|
||||||
id("maven-publish")
|
id("maven-publish")
|
||||||
|
id("com.github.johnrengelman.shadow") version "8.1.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
group = groupName
|
group = groupName
|
||||||
version = projectVersion
|
version = projectVersion
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven("https://libraries.minecraft.net")
|
maven("https://libraries.minecraft.net")
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
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")
|
implementation("com.mojang:brigadier:1.0.18")
|
||||||
// https://mvnrepository.com/artifact/io.netty/netty-all
|
// https://mvnrepository.com/artifact/io.netty/netty-all
|
||||||
implementation("io.netty:netty-all:4.1.112.Final")
|
implementation("io.netty:netty-all:4.1.112.Final")
|
||||||
// https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core
|
// https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core
|
||||||
implementation("org.apache.logging.log4j:log4j-core:2.23.1")
|
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
|
// https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2
|
||||||
implementation("com.alibaba.fastjson2:fastjson2:2.0.52")
|
implementation("com.alibaba.fastjson2:fastjson2:2.0.52")
|
||||||
// https://mvnrepository.com/artifact/org.yaml/snakeyaml
|
// https://mvnrepository.com/artifact/org.yaml/snakeyaml
|
||||||
implementation("org.yaml:snakeyaml:2.2")
|
implementation("org.yaml:snakeyaml:2.2")
|
||||||
// https://mvnrepository.com/artifact/org.jline/jline
|
// 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
|
// https://mvnrepository.com/artifact/org.projectlombok/lombok
|
||||||
compileOnly("org.projectlombok:lombok:1.18.34")
|
compileOnly("org.projectlombok:lombok:1.18.34")
|
||||||
annotationProcessor("org.projectlombok:lombok:1.18.34")
|
annotationProcessor("org.projectlombok:lombok:1.18.34")
|
||||||
testImplementation(platform("org.junit:junit-bom:5.10.0"))
|
testImplementation(platform("org.junit:junit-bom:5.10.0"))
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter")
|
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.compileJava {
|
tasks.compileJava {
|
||||||
options.encoding = "UTF-8"
|
options.encoding = "UTF-8"
|
||||||
}
|
}
|
||||||
@ -48,6 +71,21 @@ tasks.register<Jar>("sourcesJar") {
|
|||||||
archiveClassifier.set("sources")
|
archiveClassifier.set("sources")
|
||||||
from(sourceSets.main.get().allSource)
|
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 {
|
publishing {
|
||||||
publications {
|
publications {
|
||||||
create<MavenPublication>("mavenJava") {
|
create<MavenPublication>("mavenJava") {
|
||||||
@ -88,15 +126,14 @@ publishing {
|
|||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven {
|
||||||
val releasesRepoUrl = uri("http://server.wzpmc.cn:8081/repository/maven-releases")
|
val releasesRepoUrl = uri("https://wzpmc.cn:90/repository/maven-releases")
|
||||||
val snapshotsRepoUrl = uri("http://server.wzpmc.cn:8081/repository/maven-snapshots")
|
val snapshotsRepoUrl = uri("https://wzpmc.cn:90/repository/maven-snapshots")
|
||||||
url = if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl
|
url = if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl
|
||||||
|
|
||||||
credentials {
|
credentials {
|
||||||
username = project.findProperty("repo.user") as String? ?: ""
|
username = project.findProperty("repo.user") as String? ?: ""
|
||||||
password = project.findProperty("repo.password") as String? ?: ""
|
password = project.findProperty("repo.password") as String? ?: ""
|
||||||
}
|
}
|
||||||
isAllowInsecureProtocol = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
package cn.wzpmc;
|
package cn.wzpmc;
|
||||||
|
|
||||||
|
import cn.wzpmc.commands.StopCommand;
|
||||||
import cn.wzpmc.configuration.Configuration;
|
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.network.WebSocketConnectionHandler;
|
||||||
|
import cn.wzpmc.plugins.CommandManager;
|
||||||
import cn.wzpmc.utils.TemplateFileUtils;
|
import cn.wzpmc.utils.TemplateFileUtils;
|
||||||
import cn.wzpmc.utils.YamlUtils;
|
import cn.wzpmc.utils.YamlUtils;
|
||||||
import io.netty.channel.Channel;
|
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
@ -18,6 +21,8 @@ public class Main {
|
|||||||
private static final String DEFAULT_CONFIGURATION_FILE_PATH = "templates/config.yaml";
|
private static final String DEFAULT_CONFIGURATION_FILE_PATH = "templates/config.yaml";
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public static void main(String[] args) {
|
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...");
|
log.info("启动MyBot...");
|
||||||
File configurationFile = new File("config.yaml");
|
File configurationFile = new File("config.yaml");
|
||||||
if (TemplateFileUtils.saveDefaultConfig(Main.class.getClassLoader(), DEFAULT_CONFIGURATION_FILE_PATH, configurationFile)) {
|
if (TemplateFileUtils.saveDefaultConfig(Main.class.getClassLoader(), DEFAULT_CONFIGURATION_FILE_PATH, configurationFile)) {
|
||||||
@ -36,7 +41,10 @@ public class Main {
|
|||||||
}
|
}
|
||||||
WebSocketConnectionHandler webSocketConnectionHandler = new WebSocketConnectionHandler();
|
WebSocketConnectionHandler webSocketConnectionHandler = new WebSocketConnectionHandler();
|
||||||
ChannelFuture future = webSocketConnectionHandler.connect(uri);
|
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('(')
|
||||||
.append('\n');
|
.append('\n');
|
||||||
Map<String, String> data = this.getData();
|
Map<String, String> data = this.getData();
|
||||||
int i = 0;
|
|
||||||
data.forEach((key, value) -> stringBuilder.append('\t').append(key).append('=').append(value).append(',').append('\n'));
|
data.forEach((key, value) -> stringBuilder.append('\t').append(key).append('=').append(value).append(',').append('\n'));
|
||||||
int length = stringBuilder.length();
|
int length = stringBuilder.length();
|
||||||
stringBuilder.delete(length - 2, length - 1);
|
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;
|
package cn.wzpmc.api.user;
|
||||||
|
|
||||||
import cn.wzpmc.api.message.MessageComponent;
|
import cn.wzpmc.api.message.MessageComponent;
|
||||||
|
import cn.wzpmc.api.user.permission.Permissions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 消息发送者
|
* 消息发送者
|
||||||
@ -31,4 +32,22 @@ public interface CommandSender {
|
|||||||
* @param messageComponent 消息组件
|
* @param messageComponent 消息组件
|
||||||
*/
|
*/
|
||||||
void sendMessage(MessageComponent 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 指令管理器
|
* @return 指令管理器
|
||||||
*/
|
*/
|
||||||
ICommandManager getCommandManager();
|
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;
|
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
|
* @author wzp
|
||||||
* @version 0.0.1-dev
|
* @version 0.0.1-dev
|
||||||
* @since 2024/7/31 上午2:26
|
* @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.StringMessage;
|
||||||
import cn.wzpmc.api.message.json.JsonMessage;
|
import cn.wzpmc.api.message.json.JsonMessage;
|
||||||
import cn.wzpmc.api.user.IBot;
|
import cn.wzpmc.api.user.IBot;
|
||||||
|
import cn.wzpmc.api.user.permission.Permissions;
|
||||||
import cn.wzpmc.configuration.Configuration;
|
import cn.wzpmc.configuration.Configuration;
|
||||||
|
import cn.wzpmc.console.MyBotConsole;
|
||||||
import cn.wzpmc.plugins.CommandManager;
|
import cn.wzpmc.plugins.CommandManager;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -21,9 +24,13 @@ import lombok.extern.log4j.Log4j2;
|
|||||||
@Getter
|
@Getter
|
||||||
public class MyBot implements IBot {
|
public class MyBot implements IBot {
|
||||||
private final Configuration configuration;
|
private final Configuration configuration;
|
||||||
private final Long id;
|
@Setter
|
||||||
private final Long name;
|
private Long id;
|
||||||
private final CommandManager commandManager = new CommandManager();
|
@Setter
|
||||||
|
private Long name;
|
||||||
|
private final CommandManager commandManager = new CommandManager(this);
|
||||||
|
@Setter
|
||||||
|
private MyBotConsole console = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendMessage(MessageComponent messageComponent) {
|
public void sendMessage(MessageComponent messageComponent) {
|
||||||
@ -34,4 +41,16 @@ public class MyBot implements IBot {
|
|||||||
log.info(((JsonMessage) messageComponent).toTextDisplay());
|
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
|
* @author wzp
|
||||||
* @since 2024/7/30 下午11:55 v0.0.1-dev
|
* @since 2024/7/30 下午11:55 v0.0.1-dev
|
||||||
* @param websocket websocket连接地址
|
* @param websocket websocket连接地址
|
||||||
|
* @return 一个ChannelFuture对象
|
||||||
*/
|
*/
|
||||||
public ChannelFuture connect(URI websocket){
|
public ChannelFuture connect(URI websocket){
|
||||||
log.info("正在连接websocket");
|
log.info("正在连接websocket");
|
||||||
@ -44,6 +45,7 @@ public class WebSocketConnectionHandler {
|
|||||||
* @since 2024/7/31 上午2:04 v0.0.1-dev
|
* @since 2024/7/31 上午2:04 v0.0.1-dev
|
||||||
*/
|
*/
|
||||||
public void kill(){
|
public void kill(){
|
||||||
|
log.info("结束连接...");
|
||||||
this.eventLoopGroup.shutdownGracefully();
|
this.eventLoopGroup.shutdownGracefully();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,21 +2,31 @@ package cn.wzpmc.plugins;
|
|||||||
|
|
||||||
import cn.wzpmc.api.commands.BrigadierCommand;
|
import cn.wzpmc.api.commands.BrigadierCommand;
|
||||||
import cn.wzpmc.api.commands.RawCommand;
|
import cn.wzpmc.api.commands.RawCommand;
|
||||||
|
import cn.wzpmc.api.message.StringMessage;
|
||||||
import cn.wzpmc.api.plugins.ICommandManager;
|
import cn.wzpmc.api.plugins.ICommandManager;
|
||||||
import cn.wzpmc.api.user.CommandSender;
|
import cn.wzpmc.api.user.CommandSender;
|
||||||
|
import cn.wzpmc.api.user.IBot;
|
||||||
import com.mojang.brigadier.CommandDispatcher;
|
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.exceptions.CommandSyntaxException;
|
||||||
import com.mojang.brigadier.suggestion.Suggestion;
|
import com.mojang.brigadier.suggestion.Suggestion;
|
||||||
import com.mojang.brigadier.suggestion.Suggestions;
|
import com.mojang.brigadier.suggestion.Suggestions;
|
||||||
import lombok.NoArgsConstructor;
|
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
|
import lombok.ToString;
|
||||||
import lombok.extern.log4j.Log4j2;
|
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.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
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
|
* @since 2024/7/31 上午3:13
|
||||||
*/
|
*/
|
||||||
@Log4j2
|
@Log4j2
|
||||||
@NoArgsConstructor
|
public class CommandManager implements ICommandManager, Completer, Highlighter {
|
||||||
public class CommandManager implements ICommandManager {
|
|
||||||
private final CommandDispatcher<CommandSender> dispatcher = new CommandDispatcher<>();
|
private final CommandDispatcher<CommandSender> dispatcher = new CommandDispatcher<>();
|
||||||
private final ConcurrentHashMap<String, RawCommand> rawCommands = new ConcurrentHashMap<>();
|
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
|
@Override
|
||||||
public void registerCommand(RawCommand rawCommand, String name) {
|
public void registerCommand(RawCommand rawCommand, String name) {
|
||||||
if (rawCommands.containsKey(name)){
|
if (rawCommands.containsKey(name)){
|
||||||
@ -41,6 +55,7 @@ public class CommandManager implements ICommandManager {
|
|||||||
public void registerCommand(BrigadierCommand brigadierCommand){
|
public void registerCommand(BrigadierCommand brigadierCommand){
|
||||||
dispatcher.register(brigadierCommand.getCommandNode());
|
dispatcher.register(brigadierCommand.getCommandNode());
|
||||||
}
|
}
|
||||||
|
@ToString
|
||||||
private static final class CommandPart {
|
private static final class CommandPart {
|
||||||
private final String name;
|
private final String name;
|
||||||
private final List<String> args;
|
private final List<String> args;
|
||||||
@ -67,6 +82,11 @@ public class CommandManager implements ICommandManager {
|
|||||||
try {
|
try {
|
||||||
dispatcher.execute(rawCommandLine, sender);
|
dispatcher.execute(rawCommandLine, sender);
|
||||||
} catch (CommandSyntaxException e) {
|
} 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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,17 +99,83 @@ public class CommandManager implements ICommandManager {
|
|||||||
* @since 2024/7/31 上午3:36 v0.0.1-dev
|
* @since 2024/7/31 上午3:36 v0.0.1-dev
|
||||||
* @param sender 消息发送者
|
* @param sender 消息发送者
|
||||||
* @param rawCommandLine 完整命令行
|
* @param rawCommandLine 完整命令行
|
||||||
|
* @param cursor 当前光标位置
|
||||||
* @return 所有被补全的指令
|
* @return 所有被补全的指令
|
||||||
*/
|
*/
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public List<String> tabComplete(CommandSender sender, String rawCommandLine){
|
public List<String> tabComplete(CommandSender sender, String rawCommandLine, int cursor){
|
||||||
CommandPart commandPart = new CommandPart(rawCommandLine);
|
CommandPart commandPart = new CommandPart(rawCommandLine);
|
||||||
List<String> result = new ArrayList<>();
|
List<String> result = new ArrayList<>();
|
||||||
if (rawCommands.containsKey(commandPart.name)) {
|
if (rawCommands.containsKey(commandPart.name)) {
|
||||||
result.addAll(rawCommands.get(commandPart.name).onTabComplete(sender, commandPart.args));
|
result.addAll(rawCommands.get(commandPart.name).onTabComplete(sender, commandPart.args));
|
||||||
}
|
}
|
||||||
Suggestions suggestions = dispatcher.getCompletionSuggestions(dispatcher.parse(rawCommandLine, sender)).get();
|
for (Map.Entry<String, RawCommand> stringRawCommandEntry : rawCommands.entrySet()) {
|
||||||
result.addAll(suggestions.getList().stream().map(Suggestion::getText).collect(Collectors.toList()));
|
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;
|
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">
|
<Configuration status="WARN" monitorInterval="30">
|
||||||
<Appenders>
|
<Appenders>
|
||||||
<!-- 控制台输出 -->
|
<!-- 控制台输出 -->
|
||||||
<Console name="Console" target="SYSTEM_OUT">
|
<TerminalConsole name="Console">
|
||||||
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%p] %c - %m%n"/>
|
<PatternLayout pattern="%highlight{[%d{HH:mm:ss} %level]: %msg%n%xEx}" disableAnsi="${tca:disableAnsi}"/>
|
||||||
<ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
|
<ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
|
||||||
</Console>
|
</TerminalConsole>
|
||||||
|
|
||||||
<!-- 文件输出 -->
|
<!-- 文件输出 -->
|
||||||
<RollingFile name="File" fileName="./logs/latest.log"
|
<RollingFile name="File" fileName="./logs/latest.log"
|
||||||
@ -14,7 +14,7 @@
|
|||||||
<Policies>
|
<Policies>
|
||||||
<OnStartupTriggeringPolicy/>
|
<OnStartupTriggeringPolicy/>
|
||||||
<!-- 按日期滚动日志 -->
|
<!-- 按日期滚动日志 -->
|
||||||
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
|
<TimeBasedTriggeringPolicy interval="86400" modulate="true"/>
|
||||||
</Policies>
|
</Policies>
|
||||||
<DefaultRolloverStrategy fileIndex="max" max="7"/>
|
<DefaultRolloverStrategy fileIndex="max" max="7"/>
|
||||||
</RollingFile>
|
</RollingFile>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user