feat: adding base

This commit is contained in:
wzp 2024-07-31 03:51:04 +08:00
parent f0dcae301b
commit 2c39144ece
36 changed files with 898 additions and 1 deletions

8
.idea/file.template.settings.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExportableFileTemplateSettings">
<includes_templates>
<template name="version.txt" file-name="version.txt" reformat="true" live-template-enabled="false" />
</includes_templates>
</component>
</project>

View File

@ -0,0 +1,10 @@
* @author wzp
* @since ${DATE} ${TIME}
* @version #parse("version.txt")
#foreach($param in $RECORD_COMPONENTS)
* @param $param
#end
#foreach($param in $TYPE_PARAMS)
* @param <$param>
#end

View File

@ -0,0 +1,12 @@
* @author wzp
* @since ${DATE} ${TIME} v#parse("version.txt")
#foreach($param in $PARAMS)
* @param $param
#end
#foreach($param in $TYPE_PARAMS)
* @param <$param>
#end
#foreach($exception in $THROWS)
* @throws $exception
#end

View File

@ -0,0 +1,2 @@
* @since ${DATE} ${TIME} v#parse("version.txt")

View File

@ -0,0 +1,15 @@
* @author wzp
* @since ${DATE} ${TIME} v#parse("version.txt")
#foreach($param in $PARAMS)
* @param $param
#end
#if($RETURN_TYPE != "void")
* @return
#end
#foreach($param in $TYPE_PARAMS)
* @param <$param>
#end
#foreach($exception in $THROWS)
* @throws $exception
#end

View File

@ -0,0 +1,20 @@
* @author wzp
* @since ${DATE} ${TIME} v#parse("version.txt")
#foreach ($param in $PARAMS_INHERITED)
* @param $param
#end
#if (!$PARAMS_INHERITED)
#foreach ($param in $PARAMS)
* @param $param
#end
#end
#if($RETURN_TYPE != "void")
* @return
#end
#foreach($param in $TYPE_PARAMS)
* @param <$param>
#end
#foreach($exception in $THROWS)
* @throws $exception
#end

View File

@ -0,0 +1,5 @@
/**
* @author wzp
* @since ${DATE} ${TIME}
* @version #parse("version.txt")
*/

View File

@ -0,0 +1 @@
0.0.1-dev

View File

@ -16,5 +16,10 @@
<option name="name" value="MavenRepo" />
<option name="url" value="https://repo.maven.apache.org/maven2/" />
</remote-repository>
<remote-repository>
<option name="id" value="maven" />
<option name="name" value="maven" />
<option name="url" value="https://libraries.minecraft.net" />
</remote-repository>
</component>
</project>

View File

@ -13,15 +13,21 @@ version = projectVersion
repositories {
mavenCentral()
maven("https://libraries.minecraft.net")
}
dependencies {
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/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")
// https://mvnrepository.com/artifact/org.projectlombok/lombok
compileOnly("org.projectlombok:lombok:1.18.34")
annotationProcessor("org.projectlombok:lombok:1.18.34")

View File

@ -1,10 +1,42 @@
package cn.wzpmc;
import cn.wzpmc.configuration.Configuration;
import cn.wzpmc.network.WebSocketConnectionHandler;
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;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
@Log4j2
public class Main {
private static final String DEFAULT_CONFIGURATION_FILE_PATH = "templates/config.yaml";
@SneakyThrows
public static void main(String[] args) {
log.info("启动MyBot...");
File configurationFile = new File("config.yaml");
if (TemplateFileUtils.saveDefaultConfig(Main.class.getClassLoader(), DEFAULT_CONFIGURATION_FILE_PATH, configurationFile)) {
log.debug("创建日志文件成功!");
log.info("首次启动默认配置文件已创建请填写后再次启动MyBot");
return;
}
log.debug("读取配置文件 {}", configurationFile.getAbsolutePath());
Configuration configuration = YamlUtils.readYamlFile(configurationFile, Configuration.class);
URI uri;
try {
uri = new URI(configuration.getWebsocket());
} catch (URISyntaxException e) {
log.error("无法解析websocket地址");
return;
}
WebSocketConnectionHandler webSocketConnectionHandler = new WebSocketConnectionHandler();
ChannelFuture future = webSocketConnectionHandler.connect(uri);
Channel channel = future.sync().channel();
log.info("连接服务器成功!");
}
}

View File

@ -0,0 +1,10 @@
package cn.wzpmc.api.commands;
/**
* 指令基类
* @author wzp
* @version 0.0.1-dev
* @since 2024/7/31 上午3:15
*/
public interface BaseCommand {
}

View File

@ -0,0 +1,20 @@
package cn.wzpmc.api.commands;
import cn.wzpmc.api.user.CommandSender;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
/**
* Brigadier指令
* @author wzp
* @version 0.0.1-dev
* @since 2024/7/31 上午2:59
*/
public interface BrigadierCommand extends BaseCommand {
/**
* 获取指令节点
* @author wzp
* @since 2024/7/31 上午3:16 v0.0.1-dev
* @return 指令节点
*/
LiteralArgumentBuilder<CommandSender> getCommandNode();
}

View File

@ -0,0 +1,35 @@
package cn.wzpmc.api.commands;
import cn.wzpmc.api.user.CommandSender;
import java.util.List;
/**
* 原始指令
* @author wzp
* @version 0.0.1-dev
* @since 2024/7/31 上午2:27
*/
public interface RawCommand extends BaseCommand {
/**
* 当指令执行时
* @author wzp
* @since 2024/7/31 上午2:57 v0.0.1-dev
* @param commandSender 指令发送者
* @param arguments 指令参数如指令foo若执行/foo a b c则arguments为{"a", "b", "c"}
* @return 指令是否执行成功
*/
boolean onExecute(CommandSender commandSender, List<String> arguments);
/**
* 指令补全
* @author wzp
* @since 2024/7/31 上午2:58 v0.0.1-dev
* @param commandSender 指令发送者
* @param arguments 指令参数如指令foo若执行/foo a b c则arguments为{"a", "b", "c"}
* @return 当前需要提示的子命令
*/
default List<String> onTabComplete(CommandSender commandSender, List<String> arguments) {
return List.of();
}
}

View File

@ -0,0 +1,17 @@
package cn.wzpmc.api.message;
/**
* 消息对象接口
* @author wzp
* @version 0.0.1-dev
* @since 2024/7/31 上午2:33
*/
public interface MessageComponent {
/**
* 将其转换为发送的文本
* @author wzp
* @since 2024/7/31 上午2:41 v0.0.1-dev
* @return 消息文本
*/
String toMessageString();
}

View File

@ -0,0 +1,29 @@
package cn.wzpmc.api.message;
import lombok.RequiredArgsConstructor;
/**
* 纯文本消息
* @author wzp
* @version 0.0.1-dev
* @since 2024/7/31 上午2:34
*/
@RequiredArgsConstructor
public class StringMessage implements MessageComponent{
private final String message;
@Override
public String toMessageString() {
return this.message;
}
/**
* 构建纯文本消息
* @author wzp
* @since 2024/7/31 上午2:41 v0.0.1-dev
* @param message 消息文本
* @return 文本消息对象
*/
public static StringMessage text(String message){
return new StringMessage(message);
}
}

View File

@ -0,0 +1,25 @@
package cn.wzpmc.api.message.json;
import cn.wzpmc.api.message.MessageComponent;
import com.alibaba.fastjson2.JSON;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* JSON消息
* @author wzp
* @version 0.0.1-dev
* @since 2024/7/31 上午2:34
*/
public class JsonMessage implements MessageComponent {
List<JsonMessagePart> messageParts = new ArrayList<>();
@Override
public String toMessageString() {
return JSON.toJSONString(messageParts);
}
public String toTextDisplay() {
return this.messageParts.stream().map(JsonMessagePart::getTextDisplay).collect(Collectors.joining(""));
}
}

View File

@ -0,0 +1,47 @@
package cn.wzpmc.api.message.json;
import java.util.Map;
/**
* JSON消息段
* @author wzp
* @version 0.0.1-dev
* @since 2024/7/31 上午2:36
*/
public interface JsonMessagePart {
/**
* 获取消息的类型
* @author wzp
* @since 2024/7/31 上午2:40 v0.0.1-dev
* @return 消息类型字符串
*/
String getType();
/**
* 获取消息附带的数据
* @author wzp
* @since 2024/7/31 上午2:40 v0.0.1-dev
* @return 数据
*/
Map<String, String> getData();
/**
* 获取当纯文本界面的代替文本
* @author wzp
* @since 2024/7/31 上午2:45 v0.0.1-dev
* @return 文本
*/
default String getTextDisplay(){
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(this.getType())
.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);
stringBuilder.append(')');
return stringBuilder.toString();
}
}

View File

@ -0,0 +1,28 @@
package cn.wzpmc.api.plugins;
import cn.wzpmc.api.commands.BrigadierCommand;
import cn.wzpmc.api.commands.RawCommand;
/**
* 指令管理器
* @author wzp
* @version 0.0.1-dev
* @since 2024/7/31 上午3:40
*/
public interface ICommandManager {
/**
* 注册原始指令
* @author wzp
* @since 2024/7/31 上午3:34 v0.0.1-dev
* @param rawCommand 原始指令
* @param name 指令名称
*/
void registerCommand(RawCommand rawCommand, String name);
/**
* 注册Brigadier指令
* @author wzp
* @since 2024/7/31 上午3:35 v0.0.1-dev
* @param brigadierCommand 指令对象
*/
void registerCommand(BrigadierCommand brigadierCommand);
}

View File

@ -0,0 +1,23 @@
package cn.wzpmc.api.plugins.configuration;
/**
*
* @author wzp
* @version 0.0.1-dev
* @since 2024/7/31 上午3:42
*/
public interface IAuthorizationConfiguration {
/**
* @author wzp
* @since 2024/7/31 上午3:45 v0.0.1-dev
* @return 是否启用
*/
boolean isEnable();
/**
* @author wzp
* @since 2024/7/31 上午3:45 v0.0.1-dev
* @return token
*/
String getToken();
}

View File

@ -0,0 +1,30 @@
package cn.wzpmc.api.plugins.configuration;
/**
* 配置
* @author wzp
* @version 0.0.1-dev
* @since 2024/7/31 上午3:42
*/
public interface IConfiguration {
/**
* @author wzp
* @since 2024/7/31 上午3:48 v0.0.1-dev
* @return WebSocket连接URL
*/
String getWebsocket();
/**
* @author wzp
* @since 2024/7/31 上午3:48 v0.0.1-dev
* @return 通信验证
*/
IAuthorizationConfiguration getAuthorization();
/**
* @author wzp
* @since 2024/7/31 上午3:49 v0.0.1-dev
* @return 失败消息提示
*/
IFallbackConfiguration getFallback();
}

View File

@ -0,0 +1,23 @@
package cn.wzpmc.api.plugins.configuration;
/**
* 通信验证配置
* @author wzp
* @version 0.0.1-dev
* @since 2024/7/31 上午3:43
*/
public interface IFallbackConfiguration {
/**
* @author wzp
* @since 2024/7/31 上午3:47 v0.0.1-dev
* @return 当指令执行失败时
*/
String getCommand();
/**
* @author wzp
* @since 2024/7/31 上午3:47 v0.0.1-dev
* @return 当出现未捕获的异常时
*/
String getErrorUncaught();
}

View File

@ -0,0 +1,34 @@
package cn.wzpmc.api.user;
import cn.wzpmc.api.message.MessageComponent;
/**
* 消息发送者
* @author wzp
* @version 0.0.1-dev
* @since 2024/7/31 上午2:32
*/
public interface CommandSender {
/**
* 获取用户ID
* @author wzp
* @since 2024/7/30 下午11:48 v0.0.1-dev
* @return 用户ID
*/
Long getId();
/**
* 获取用户名
* @author wzp
* @since 2024/7/30 下午11:48 v0.0.1-dev
* @return 用户名
*/
Long getName();
/**
* 发送消息
* @author wzp
* @since 2024/7/31 上午2:42 v0.0.1-dev
* @param messageComponent 消息组件
*/
void sendMessage(MessageComponent messageComponent);
}

View File

@ -0,0 +1,28 @@
package cn.wzpmc.api.user;
import cn.wzpmc.api.plugins.ICommandManager;
import cn.wzpmc.api.plugins.configuration.IConfiguration;
/**
* 机器人接口
* @author wzp
* @version 0.0.1-dev
* @since 2024/7/31 上午2:31
*/
public interface IBot extends CommandSender {
/**
* 获取配置文件
* @author wzp
* @since 2024/7/31 上午2:55 v0.0.1-dev
* @return 配置文件
*/
IConfiguration getConfiguration();
/**
* 获取指令管理器
* @author wzp
* @since 2024/7/31 上午3:42 v0.0.1-dev
* @return 指令管理器
*/
ICommandManager getCommandManager();
}

View File

@ -0,0 +1,11 @@
package cn.wzpmc.api.user;
/**
* 用户接口
* @author wzp
* @version 0.0.1-dev
* @since 2024/7/30 下午11:42
*/
public interface IUser extends CommandSender {
}

View File

@ -0,0 +1,9 @@
package cn.wzpmc.commands;
/**
* @author wzp
* @version 0.0.1-dev
* @since 2024/7/31 上午2:26
*/
public class StopCommand {
}

View File

@ -0,0 +1,24 @@
package cn.wzpmc.configuration;
import cn.wzpmc.api.plugins.configuration.IAuthorizationConfiguration;
import lombok.*;
/**
* 通信验证配置类
* @author wzp
* @since 2024/7/30 下午11:50
* @version 0.0.1-dev
*/
@Data
public class AuthorizationConfiguration implements IAuthorizationConfiguration {
/**
* 是否启用
* @since 2024/7/30 下午11:50 v0.0.1-dev
*/
private boolean enable;
/**
* token
* @since 2024/7/30 下午11:50 v0.0.1-dev
*/
private String token;
}

View File

@ -0,0 +1,29 @@
package cn.wzpmc.configuration;
import cn.wzpmc.api.plugins.configuration.IConfiguration;
import lombok.*;
/**
* 配置类
* @author wzp
* @since 2024/7/30 下午11:48
* @version 0.0.1-dev
*/
@Data
public class Configuration implements IConfiguration {
/**
* WebSocket连接URL
* @since 2024/7/30 下午11:48 v0.0.1-dev
*/
private String websocket;
/**
* 通信验证
* @since 2024/7/30 下午11:49 v0.0.1-dev
*/
private AuthorizationConfiguration authorization;
/**
* 失败消息提示
* @since 2024/7/30 下午11:49 v0.0.1-dev
*/
private FallbackConfiguration fallback;
}

View File

@ -0,0 +1,24 @@
package cn.wzpmc.configuration;
import cn.wzpmc.api.plugins.configuration.IFallbackConfiguration;
import lombok.*;
/**
* 当失败时报错消息配置实现
* @author wzp
* @since 2024/7/31 上午3:44
* @version 0.0.1-dev
*/
@Data
public class FallbackConfiguration implements IFallbackConfiguration {
/**
* 当指令执行失败时
* @since 2024/7/31 上午3:44 v0.0.1-dev
*/
private String command;
/**
* 当出现未捕获的异常时
* @since 2024/7/31 上午3:44 v0.0.1-dev
*/
private String errorUncaught;
}

View File

@ -0,0 +1,37 @@
package cn.wzpmc.entities.user.bot;
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.configuration.Configuration;
import cn.wzpmc.plugins.CommandManager;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
/**
* 机器人实现类
* @author wzp
* @since 2024/7/30 下午11:46
* @version 0.0.1-dev
*/
@Log4j2
@RequiredArgsConstructor
@Getter
public class MyBot implements IBot {
private final Configuration configuration;
private final Long id;
private final Long name;
private final CommandManager commandManager = new CommandManager();
@Override
public void sendMessage(MessageComponent messageComponent) {
if (messageComponent instanceof StringMessage){
log.info(messageComponent.toMessageString());
}
if (messageComponent instanceof JsonMessage){
log.info(((JsonMessage) messageComponent).toTextDisplay());
}
}
}

View File

@ -0,0 +1,31 @@
package cn.wzpmc.network;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
/**
* @author wzp
* @version 0.0.1-dev
* @since 2024/7/31 上午12:14
*/
@Log4j2
@RequiredArgsConstructor
public class PacketHandler extends SimpleChannelInboundHandler<WebSocketFrame> {
private final WebSocketClientHandshaker handshaker;
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
log.debug("开始WebSocket握手");
this.handshaker.handshake(ctx.channel());
log.debug("握手完成");
}
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, WebSocketFrame webSocketFrame) throws Exception {
System.out.println(webSocketFrame);
}
}

View File

@ -0,0 +1,29 @@
package cn.wzpmc.network;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.stream.ChunkedWriteHandler;
import lombok.RequiredArgsConstructor;
/**
* WebSocket连接初始化
* @author wzp
* @version 0.0.1-dev
* @since 2024/7/31 上午1:19
*/
@RequiredArgsConstructor
public class WebSocketChannelInitializer extends ChannelInitializer<SocketChannel> {
private final ChannelHandler handler;
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new HttpClientCodec());
pipeline.addLast(new ChunkedWriteHandler());
pipeline.addLast(new HttpObjectAggregator(64 * 1024));
pipeline.addLast(handler);
}
}

View File

@ -0,0 +1,49 @@
package cn.wzpmc.network;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
import lombok.extern.log4j.Log4j2;
import java.net.URI;
import java.util.concurrent.Future;
/**
* 此类用于建立WebSocket连接
* @author wzp
* @version 0.0.1-dev
* @since 2024/7/30 下午11:54
*/
@Log4j2
public class WebSocketConnectionHandler {
private final EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
/**
* 建立连接
* @author wzp
* @since 2024/7/30 下午11:55 v0.0.1-dev
* @param websocket websocket连接地址
*/
public ChannelFuture connect(URI websocket){
log.info("正在连接websocket");
Bootstrap bootstrap = new Bootstrap();
WebSocketClientHandshaker clientHandshaker = WebSocketClientHandshakerFactory.newHandshaker(websocket, WebSocketVersion.V13, null, false, new DefaultHttpHeaders());
PacketHandler handler = new PacketHandler(clientHandshaker);
bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class).handler(new WebSocketChannelInitializer(handler));
return bootstrap.connect(websocket.getHost(), websocket.getPort());
}
/**
* 强制结束通信
* @author wzp
* @since 2024/7/31 上午2:04 v0.0.1-dev
*/
public void kill(){
this.eventLoopGroup.shutdownGracefully();
}
}

View File

@ -0,0 +1,96 @@
package cn.wzpmc.plugins;
import cn.wzpmc.api.commands.BrigadierCommand;
import cn.wzpmc.api.commands.RawCommand;
import cn.wzpmc.api.plugins.ICommandManager;
import cn.wzpmc.api.user.CommandSender;
import com.mojang.brigadier.CommandDispatcher;
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.NoArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
* 指令管理器实现类
* @author wzp
* @version 0.0.1-dev
* @since 2024/7/31 上午3:13
*/
@Log4j2
@NoArgsConstructor
public class CommandManager implements ICommandManager {
private final CommandDispatcher<CommandSender> dispatcher = new CommandDispatcher<>();
private final ConcurrentHashMap<String, RawCommand> rawCommands = new ConcurrentHashMap<>();
@Override
public void registerCommand(RawCommand rawCommand, String name) {
if (rawCommands.containsKey(name)){
log.error("指令{}已经被注册,注册失败!", name);
return;
}
this.rawCommands.put(name, rawCommand);
}
@Override
public void registerCommand(BrigadierCommand brigadierCommand){
dispatcher.register(brigadierCommand.getCommandNode());
}
private static final class CommandPart {
private final String name;
private final List<String> args;
public CommandPart(String rawCommandLine) {
List<String> list = Arrays.asList(rawCommandLine.split(" "));
this.name = list.get(0);
this.args = list.subList(1, list.size());
}
}
/**
* 执行指令
* @author wzp
* @since 2024/7/31 上午3:35 v0.0.1-dev
* @param sender 发送者
* @param rawCommandLine 完整命令行
* @return 是否执行成功
*/
public boolean execute(CommandSender sender, String rawCommandLine){
CommandPart commandPart = new CommandPart(rawCommandLine);
if (rawCommands.containsKey(commandPart.name)) {
return rawCommands.get(commandPart.name).onExecute(sender, commandPart.args);
}else {
try {
dispatcher.execute(rawCommandLine, sender);
} catch (CommandSyntaxException e) {
return false;
}
}
return true;
}
/**
* tab补全的结果
* @author wzp
* @since 2024/7/31 上午3:36 v0.0.1-dev
* @param sender 消息发送者
* @param rawCommandLine 完整命令行
* @return 所有被补全的指令
*/
@SneakyThrows
public List<String> tabComplete(CommandSender sender, String rawCommandLine){
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()));
return result;
}
}

View File

@ -0,0 +1,43 @@
package cn.wzpmc.utils;
import lombok.extern.log4j.Log4j2;
import java.io.*;
/**
* 模板文件工具类
* @author wzp
* @since 2024/07/30 23:28:25
* @version 0.0.1-dev
*/
@Log4j2
public class TemplateFileUtils {
/**
* 写入默认配置文件
* @param loader 读取默认配置所使用的类加载器
* @param path 默认配置的路径
* @param saved 保存到的文件
* @return 是否写入
*/
public static boolean saveDefaultConfig(ClassLoader loader, String path, File saved){
log.debug("创建默认配置文件从ClassLoader {} -> {} ==> {}", loader, path, saved);
try(InputStream sourceInputStream = loader.getResourceAsStream(path)){
if (sourceInputStream == null){
throw new RuntimeException(new FileNotFoundException("Didn't find " + path + " from class loader: " + loader.getName()));
}
if (saved.exists()){
return false;
}
if (!saved.createNewFile()) {
throw new IOException("Cannot create file " + saved.getAbsolutePath());
}
try(FileOutputStream targetFileStream = new FileOutputStream(saved)){
sourceInputStream.transferTo(targetFileStream);
}
return true;
} catch (IOException e) {
log.throwing(e);
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,50 @@
package cn.wzpmc.utils;
import lombok.extern.log4j.Log4j2;
import org.yaml.snakeyaml.Yaml;
import java.io.*;
/**
* Yaml工具类
* @author wzp
* @since 2024/7/30 下午11:46
* @version 0.0.1-dev
*/
@Log4j2
public class YamlUtils {
/**
* 读取Yaml文件并将其序列化为一个类
* @param file yaml文件
* @param clazz 需要序列化的类
* @return 一个对象
* @param <T> 序列化的类型(需要空参构造方法)
*/
public static <T> T readYamlFile(File file, Class<T> clazz){
log.debug("读取Yaml文件 {},并写入到类 {}", file, clazz);
try(FileInputStream fis = new FileInputStream(file)){
Yaml yaml = new Yaml();
return yaml.loadAs(fis, clazz);
} catch (IOException e) {
log.throwing(e);
throw new RuntimeException(e);
}
}
/**
* 将一个类序列化为Yaml文件
* @param file yaml文件
* @param obj 数据类
* @param <T> 序列化的对象
*/
public static <T> void writeYamlFile(File file, T obj){
log.debug("将对象:{} 写入Yaml文件{}中", obj, file);
try(FileWriter writer = new FileWriter(file)){
Yaml yaml = new Yaml();
yaml.dump(obj, writer);
} catch (IOException e) {
log.throwing(e);
throw new RuntimeException(e);
}
}
}