1.0
This commit is contained in:
commit
f57af31969
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
/.idea/
|
||||
/target/
|
||||
/ElementOriginLib.iml
|
140
pom.xml
Normal file
140
pom.xml
Normal file
|
@ -0,0 +1,140 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.io.yutian.elementoriginlib</groupId>
|
||||
<artifactId>ElementOriginLib</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ElementOriginLib</name>
|
||||
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<defaultGoal>clean package</defaultGoal>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.13.0</version>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.5.3</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>papermc-repo</id>
|
||||
<url>https://repo.papermc.io/repository/maven-public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>sonatype</id>
|
||||
<url>https://oss.sonatype.org/content/groups/public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>public</id>
|
||||
<url>https://repo.aurora-pixels.com/repository/public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>public-rpg</id>
|
||||
<url>https://repo.aurora-pixels.com/repository/public-rpg/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spigotmc-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>rapture-snapshots</id>
|
||||
<url>https://repo.rapture.pw/repository/maven-snapshots/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.papermc.paper</groupId>
|
||||
<artifactId>paper-api</artifactId>
|
||||
<version>1.20.1-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>1.20.1</version>
|
||||
<classifier>nms</classifier>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mojang</groupId>
|
||||
<artifactId>authlib</artifactId>
|
||||
<version>3.3.39</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mojang</groupId>
|
||||
<artifactId>brigadier</artifactId>
|
||||
<version>1.0.18</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mojang</groupId>
|
||||
<artifactId>datafixerupper</artifactId>
|
||||
<version>4.1.27</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-compress</artifactId>
|
||||
<version>1.26.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.luben</groupId>
|
||||
<artifactId>zstd-jni</artifactId>
|
||||
<version>1.5.6-3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.zaxxer</groupId>
|
||||
<artifactId>HikariCP</artifactId>
|
||||
<version>4.0.3</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.xerial/sqlite-jdbc -->
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
<artifactId>sqlite-jdbc</artifactId>
|
||||
<version>3.46.0.0</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
|
||||
<dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
<version>5.1.3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,21 @@
|
|||
package com.io.yutian.elementoriginlib;
|
||||
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public final class ElementOriginLib extends JavaPlugin {
|
||||
|
||||
private static ElementOriginLib instance;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
}
|
||||
|
||||
public static ElementOriginLib inst() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.io.yutian.elementoriginlib.command;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Command<S extends CommandContext> {
|
||||
|
||||
void run(S context);
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package com.io.yutian.elementoriginlib.command;
|
||||
|
||||
import com.io.yutian.elementoriginlib.command.argument.ArgumentValue;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class CommandContext {
|
||||
|
||||
private String command;
|
||||
private String label;
|
||||
private CommandSender sender;
|
||||
private Map<String, ArgumentValue> argumentsValues;
|
||||
|
||||
public CommandContext(String command, String label, CommandSender sender, Map<String, ArgumentValue> argumentsValues) {
|
||||
this.command = command;
|
||||
this.label = label;
|
||||
this.sender = sender;
|
||||
this.argumentsValues = argumentsValues;
|
||||
}
|
||||
|
||||
public String getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public CommandSender getSender() {
|
||||
return sender;
|
||||
}
|
||||
|
||||
public ArgumentValue getArgumentsValue(String key) {
|
||||
return argumentsValues.getOrDefault(key, new ArgumentValue(null));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
package com.io.yutian.elementoriginlib.command;
|
||||
|
||||
import com.io.yutian.elementoriginlib.command.argument.Argument;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class CommandNode {
|
||||
|
||||
private String name;
|
||||
|
||||
private List<CommandNode> childrens = new ArrayList<>();
|
||||
private List<Argument> arguments = new ArrayList<>();
|
||||
|
||||
private List<String> alias = new ArrayList<>();
|
||||
|
||||
private Predicate<CommandSender> commandSenderPredicate = (commandSender -> true);
|
||||
private Command command;
|
||||
|
||||
public CommandNode(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public CommandNode(String name, String[] alias) {
|
||||
this.name = name;
|
||||
this.alias = Arrays.asList(alias);
|
||||
}
|
||||
|
||||
public CommandNode(String name, List<String> alias) {
|
||||
this.name = name;
|
||||
this.alias = alias;
|
||||
}
|
||||
|
||||
public CommandNode permission(Predicate<CommandSender> commandSenderPredicate) {
|
||||
this.commandSenderPredicate = commandSenderPredicate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<String> getAlias() {
|
||||
return alias;
|
||||
}
|
||||
|
||||
public CommandNode setAlias(List<String> alias) {
|
||||
this.alias = alias;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandNode addAilas(String alias) {
|
||||
this.alias.add(alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandNode addArgument(Argument argument) {
|
||||
arguments.add(argument);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandNode addChildren(CommandNode commandNode) {
|
||||
this.childrens.add(commandNode);
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<CommandNode> getChildrens() {
|
||||
return childrens;
|
||||
}
|
||||
|
||||
public List<Argument> getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public CommandNode executes(Command command) {
|
||||
this.command = command;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Command getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public static CommandNode node(String name) {
|
||||
return new CommandNode(name);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.io.yutian.elementoriginlib.command;
|
||||
|
||||
public interface IAlias {
|
||||
|
||||
String[] getAlias();
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package com.io.yutian.elementoriginlib.command;
|
||||
|
||||
import com.io.yutian.elementoriginlib.command.argument.Argument;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class ICommand {
|
||||
|
||||
private String name;
|
||||
private String description;
|
||||
|
||||
private List<CommandNode> commandNodes = new ArrayList<>();
|
||||
private List<Argument> arguments = new ArrayList<>();
|
||||
|
||||
public ICommand(String name) {
|
||||
this(name, null);
|
||||
}
|
||||
|
||||
public ICommand(String name, String description) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public void executes(CommandContext commandContext) {
|
||||
}
|
||||
|
||||
public boolean emptyExecutes(CommandSender commandSender) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasPermission(CommandSender sender) {
|
||||
return sender.isOp() || sender.hasPermission(getPermissionPrefix()+"."+name);
|
||||
}
|
||||
|
||||
public String getPermissionPrefix() {
|
||||
return "command."+name;
|
||||
}
|
||||
|
||||
public ICommand addArgument(Argument argument) {
|
||||
arguments.add(argument);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ICommand addCommandNode(CommandNode commandNode) {
|
||||
this.commandNodes.add(commandNode);
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<CommandNode> getCommandNodes() {
|
||||
return commandNodes;
|
||||
}
|
||||
|
||||
public List<Argument> getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.io.yutian.elementoriginlib.command;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ICommandManager {
|
||||
|
||||
String getName();
|
||||
|
||||
List<ICommand> getCommands();
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package com.io.yutian.elementoriginlib.command;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public interface ITabCompleter {
|
||||
|
||||
List<String> onTabComplete(CommandSender commandSender, String[] args, int index, String lastArg);
|
||||
|
||||
static List<String> getPlayerList(String arg) {
|
||||
List<String> list = new ArrayList<>();
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
String name = player.getName();
|
||||
if (arg != null && !arg.trim().equalsIgnoreCase("")) {
|
||||
if (name.toLowerCase().startsWith(arg.toLowerCase())) {
|
||||
list.add(name);
|
||||
}
|
||||
} else {
|
||||
list.add(name);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,295 @@
|
|||
package com.io.yutian.elementoriginlib.command;
|
||||
|
||||
import com.io.yutian.elementoriginlib.command.argument.Argument;
|
||||
import com.io.yutian.elementoriginlib.command.argument.ArgumentValue;
|
||||
import com.io.yutian.elementoriginlib.command.handler.CommandHandler;
|
||||
import com.io.yutian.elementoriginlib.lang.Lang;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class SimpleCommandHandler extends Command {
|
||||
|
||||
private ICommand iCommand;
|
||||
|
||||
public SimpleCommandHandler(String name, ICommand iCommand) {
|
||||
super(name);
|
||||
this.iCommand = iCommand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(CommandSender sender, String commandLabel, String[] args) {
|
||||
executes(sender, commandLabel, args);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void executes(CommandSender sender, String commandLabel, String[] args) {
|
||||
if (!iCommand.hasPermission(sender)) {
|
||||
sender.sendMessage(Lang.get("command-no-permission"));
|
||||
return;
|
||||
}
|
||||
List<CommandNode> commandNodes = iCommand.getCommandNodes();
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
stringBuilder.append(args[i]);
|
||||
if (i < args.length - 1) {
|
||||
stringBuilder.append(" ");
|
||||
}
|
||||
}
|
||||
String commandString = stringBuilder.toString();
|
||||
if (commandNodes.size() == 0) {
|
||||
Map<String, ArgumentValue> map = new HashMap<>();
|
||||
if (iCommand.getArguments().size() > 0) {
|
||||
int argSize = args.length;
|
||||
List<Argument> arguments = iCommand.getArguments();
|
||||
int k = 0;
|
||||
if (arguments.get(arguments.size()-1).isOptional()) {
|
||||
k++;
|
||||
}
|
||||
if (argSize < arguments.size()-k) {
|
||||
sender.sendMessage(Lang.get("command-short-arg"));
|
||||
return;
|
||||
}
|
||||
for (int l = 0; l < arguments.size(); l++) {
|
||||
Argument a = arguments.get(l);
|
||||
int index = l;
|
||||
if (index >= args.length) {
|
||||
break;
|
||||
}
|
||||
String arg = args[index];
|
||||
if (!a.getArgumentsType().test(arg)) {
|
||||
sender.sendMessage(Lang.get("command-unknown-arg", index+1, arg));
|
||||
return;
|
||||
}
|
||||
}
|
||||
map = parseArgumentValue(sender, arguments, args, -1);
|
||||
}
|
||||
iCommand.executes(new CommandContext(commandString, commandLabel, sender, map));
|
||||
return;
|
||||
}
|
||||
|
||||
int nodeSize = args.length;
|
||||
|
||||
if (commandNodes.size() > 0 && nodeSize == 0) {
|
||||
if (!iCommand.emptyExecutes(sender)) {
|
||||
sender.sendMessage(Lang.get("command-short-arg"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
String mainNode = args[0];
|
||||
|
||||
Stream<CommandNode> nodeStream = commandNodes.stream().filter((n) -> {
|
||||
return n.getName().equalsIgnoreCase(mainNode) || n.getAlias().contains(mainNode);
|
||||
});
|
||||
Optional<CommandNode> nodeOptional = nodeStream.findFirst();
|
||||
if (!nodeOptional.isPresent()) {
|
||||
sender.sendMessage(Lang.get("command-unknown-arg", 1, mainNode));
|
||||
return;
|
||||
}
|
||||
CommandNode node = nodeOptional.get();
|
||||
|
||||
if (node.getChildrens().size() > 0) {
|
||||
checkClidren(commandString, commandLabel, sender, 0, args, node);
|
||||
} else {
|
||||
if (node.getCommand() != null) {
|
||||
Map<String, ArgumentValue> map = new HashMap<>();
|
||||
if (node.getArguments().size() > 0) {
|
||||
int argSize = args.length - 1;
|
||||
List<Argument> arguments = node.getArguments();
|
||||
int k = 0;
|
||||
if (arguments.get(arguments.size()-1).isOptional()) {
|
||||
k++;
|
||||
}
|
||||
if (argSize < arguments.size()-k) {
|
||||
sender.sendMessage(Lang.get("command-short-arg"));
|
||||
return;
|
||||
}
|
||||
for (int l = 0; l < arguments.size(); l++) {
|
||||
Argument a = arguments.get(l);
|
||||
int index = l + 1;
|
||||
if (index >= args.length) {
|
||||
break;
|
||||
}
|
||||
String arg = args[index];
|
||||
if (!a.getArgumentsType().test(arg)) {
|
||||
sender.sendMessage(Lang.get("command-error-arg", index+1, arg));
|
||||
return;
|
||||
}
|
||||
}
|
||||
map = parseArgumentValue(sender, node.getArguments(), args, 0);
|
||||
}
|
||||
node.getCommand().run(new CommandContext(commandString, commandLabel, sender, map));
|
||||
} else {
|
||||
sender.sendMessage(Lang.get("command-unknown-arg", 2, mainNode));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void checkClidren(String commandString, String commandLabel, CommandSender sender, int i, String[] args, CommandNode node) {
|
||||
i++;
|
||||
if (i >= args.length) {
|
||||
if (node.getCommand() == null) {
|
||||
sender.sendMessage(Lang.get("command-short-arg"));
|
||||
} else {
|
||||
node.getCommand().run(new CommandContext(commandString, commandLabel, sender, new HashMap<>()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
String s = args[i];
|
||||
Stream<CommandNode> nodeStream = node.getChildrens().stream().filter((n) -> {
|
||||
return n.getName().equalsIgnoreCase(s) || n.getAlias().contains(s);
|
||||
});
|
||||
Optional<CommandNode> nodeOptional = nodeStream.findFirst();
|
||||
if (!nodeOptional.isPresent()) {
|
||||
sender.sendMessage(Lang.get("command-unknown-arg", i+1, s));
|
||||
return;
|
||||
}
|
||||
CommandNode node1 = nodeOptional.get();
|
||||
|
||||
if (node1.getChildrens().size() > 0) {
|
||||
checkClidren(commandString, commandLabel, sender, i, args, node1);
|
||||
} else {
|
||||
if (node1.getCommand() != null) {
|
||||
Map<String, ArgumentValue> map = new HashMap<>();
|
||||
if (node1.getArguments().size() > 0) {
|
||||
int argSize = args.length - i - 1;
|
||||
List<Argument> arguments = node1.getArguments();
|
||||
int k = 0;
|
||||
if (arguments.get(arguments.size()-1).isOptional()) {
|
||||
k++;
|
||||
}
|
||||
if (argSize < arguments.size()-k) {
|
||||
sender.sendMessage(Lang.get("command-short-arg"));
|
||||
return;
|
||||
}
|
||||
for (int l = 0; l < arguments.size(); l++) {
|
||||
Argument a = arguments.get(l);
|
||||
int index = i + l + 1;
|
||||
if (index >= args.length) {
|
||||
break;
|
||||
}
|
||||
String arg = args[index];
|
||||
if (!a.getArgumentsType().test(arg)) {
|
||||
sender.sendMessage(Lang.get("command-unknown-arg", index+1, arg));
|
||||
return;
|
||||
}
|
||||
}
|
||||
map = parseArgumentValue(sender, node1.getArguments(), args, i);
|
||||
}
|
||||
node1.getCommand().run(new CommandContext(commandString, commandLabel, sender, map));
|
||||
} else {
|
||||
sender.sendMessage(Lang.get("command-unknown-arg", i+1, s));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Map<String, ArgumentValue> parseArgumentValue(CommandSender commandSender, List<Argument> argumentList, String[] args, int i) {
|
||||
Map<String, ArgumentValue> map = new HashMap<>();
|
||||
List<Argument> arguments = argumentList;
|
||||
for (int l = 0; l < arguments.size(); l++) {
|
||||
Argument a = arguments.get(l);
|
||||
if (i+1+l >= args.length) {
|
||||
if (a.isOptional()) {
|
||||
map.put(a.getName(), new ArgumentValue(a.getDefaultValue()));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
String arg = args[i+1+l];
|
||||
if (!a.getArgumentsType().test(arg)) {
|
||||
continue;
|
||||
}
|
||||
ArgumentValue argumentValue = new ArgumentValue(a.getArgumentsType().get(arg));
|
||||
map.put(a.getName(), argumentValue);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
|
||||
return onTabComplete(sender, alias, args);
|
||||
}
|
||||
|
||||
public List<String> onTabComplete(CommandSender sender, String alias, String[] args) {
|
||||
List<String> list = new ArrayList<>();
|
||||
int index = args.length;
|
||||
String arg = args[index-1];
|
||||
if (!iCommand.hasPermission(sender)) {
|
||||
return list;
|
||||
}
|
||||
if (iCommand instanceof ITabCompleter) {
|
||||
ITabCompleter tabCompleter = (ITabCompleter) iCommand;
|
||||
return tabCompleter.onTabComplete(sender, args, index-1, arg);
|
||||
} else {
|
||||
Map<Integer, List<String>> map = new HashMap<>();
|
||||
if (iCommand.getCommandNodes().size() > 0) {
|
||||
List<String> list1 = new ArrayList<>();
|
||||
for (CommandNode node : iCommand.getCommandNodes()) {
|
||||
list1.add(node.getName());
|
||||
list1.addAll(node.getAlias());
|
||||
if (index >= 2) {
|
||||
if (!node.getName().equalsIgnoreCase(args[0])) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (node.getChildrens().size() > 0) {
|
||||
getTabComplete(node, 1, map);
|
||||
} else if (node.getArguments().size() > 0) {
|
||||
List<Argument> arguments = node.getArguments();
|
||||
for (int l = 0; l < arguments.size(); l++) {
|
||||
Argument argument = arguments.get(l);
|
||||
if (argument.getSuggest() != null) {
|
||||
map.put(2+l, argument.getSuggest().getSuggest());
|
||||
continue;
|
||||
}
|
||||
map.put(2+l, Arrays.asList("<"+argument.getName()+">"));
|
||||
}
|
||||
}
|
||||
}
|
||||
map.put(1, list1);
|
||||
return CommandHandler.preseSuggest(map.getOrDefault(index, list), arg);
|
||||
} else if (iCommand.getArguments().size() > 0) {
|
||||
List<Argument> arguments = iCommand.getArguments();
|
||||
for (int l = 0; l < arguments.size(); l++) {
|
||||
Argument argument = arguments.get(l);
|
||||
if (argument.getSuggest() != null) {
|
||||
map.put(0+l+1, argument.getSuggest().getSuggest());
|
||||
continue;
|
||||
}
|
||||
map.put(0+l+1, Arrays.asList("<"+argument.getName()+">"));
|
||||
}
|
||||
return CommandHandler.preseSuggest(map.getOrDefault(index, list), arg);
|
||||
}
|
||||
}
|
||||
return CommandHandler.preseSuggest(list, arg);
|
||||
}
|
||||
|
||||
private void getTabComplete(CommandNode node, int i, Map<Integer, List<String>> map) {
|
||||
i++;
|
||||
List<String> list = map.getOrDefault(i, new ArrayList<>());
|
||||
for (CommandNode c : node.getChildrens()) {
|
||||
list.add(c.getName());
|
||||
if (c.getChildrens().size() > 0) {
|
||||
getTabComplete(c, i, map);
|
||||
} else if (c.getArguments().size() > 0) {
|
||||
List<Argument> arguments = c.getArguments();
|
||||
for (int l = 0; l < arguments.size(); l++) {
|
||||
Argument argument = arguments.get(l);
|
||||
if (argument.getSuggest() != null) {
|
||||
map.put(i+l+1, argument.getSuggest().getSuggest());
|
||||
continue;
|
||||
}
|
||||
map.put(i+l+1, Arrays.asList("<"+argument.getName()+">"));
|
||||
}
|
||||
}
|
||||
}
|
||||
map.put(i, list);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
package com.io.yutian.elementoriginlib.command;
|
||||
|
||||
import com.io.yutian.elementoriginlib.command.handler.CommandHandler;
|
||||
import com.io.yutian.elementoriginlib.command.list.CommandHelp;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandMap;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class SimpleCommandManager implements ICommandManager {
|
||||
|
||||
protected static Map<String, Command> bukkitCommandMap = new HashMap<>();
|
||||
protected static CommandMap commandMap;
|
||||
|
||||
private final Plugin plugin;
|
||||
private final String name;
|
||||
|
||||
@NotNull
|
||||
private List<ICommand> commands;
|
||||
|
||||
|
||||
public SimpleCommandManager(Plugin plugin, String name) {
|
||||
this(plugin, name, new ArrayList<>());
|
||||
}
|
||||
|
||||
public SimpleCommandManager(Plugin plugin, String name, @NotNull List<ICommand> commands) {
|
||||
this.plugin = plugin;
|
||||
this.name = name;
|
||||
this.commands = commands;
|
||||
register(new CommandHelp(this));
|
||||
}
|
||||
|
||||
public void register(@NotNull ICommand command) {
|
||||
if (command == null) {
|
||||
return;
|
||||
}
|
||||
commands.add(command);
|
||||
if (command instanceof IAlias alias) {
|
||||
String[] array = alias.getAlias();
|
||||
for (String s : array) {
|
||||
registerPluginBukkitCommand(plugin, s, command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterAll() {
|
||||
for (ICommand command : commands) {
|
||||
if (command instanceof IAlias) {
|
||||
unregister(command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void unregister(ICommand command) {
|
||||
if (!(command instanceof IAlias)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Map<String, Command> map = (Map<String, Command>) commandMap.getClass().getMethod("getKnownCommands").invoke(commandMap);
|
||||
for (String name : ((IAlias) command).getAlias()) {
|
||||
map.remove(name);
|
||||
Command bukkitCommand = bukkitCommandMap.get(name);
|
||||
bukkitCommand.unregister(commandMap);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void registerPluginCommand(@NotNull Plugin plugin, String commandName) {
|
||||
Bukkit.getPluginCommand(commandName).setExecutor(new CommandHandler(plugin, this));
|
||||
}
|
||||
|
||||
protected static void registerPluginBukkitCommand(Plugin plugin, String name, ICommand command) {
|
||||
SimpleCommandHandler simpleCommandHandler = new SimpleCommandHandler(name, command);
|
||||
bukkitCommandMap.put(name, simpleCommandHandler);
|
||||
commandMap.register(plugin.getName(), simpleCommandHandler);
|
||||
}
|
||||
|
||||
public Plugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<ICommand> getCommands() {
|
||||
return commands;
|
||||
}
|
||||
|
||||
static {
|
||||
try {
|
||||
Class<?> c = Bukkit.getServer().getClass();
|
||||
for (Method method : c.getDeclaredMethods()) {
|
||||
if (method.getName().equals("getCommandMap")) {
|
||||
commandMap = (CommandMap) method.invoke(Bukkit.getServer(), new Object[0]);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.io.yutian.elementoriginlib.command;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Suggest {
|
||||
|
||||
List<String> getSuggest();
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package com.io.yutian.elementoriginlib.command;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class Suggests {
|
||||
|
||||
public static final Suggest WORLD_LIST = ()->{
|
||||
List<String> list = new LinkedList<>();
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
list.add(world.getName());
|
||||
}
|
||||
return list;
|
||||
};
|
||||
|
||||
public static final Suggest PLAYER_LIST = ()->{
|
||||
List<String> list = new LinkedList<>();
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
list.add(player.getName());
|
||||
}
|
||||
return list;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.io.yutian.elementoriginlib.command.argument;
|
||||
|
||||
import com.io.yutian.elementoriginlib.command.Suggest;
|
||||
|
||||
public class Argument {
|
||||
|
||||
private String name;
|
||||
|
||||
private ArgumentType argumentsType;
|
||||
|
||||
private Suggest suggest;
|
||||
|
||||
private boolean optional = false;
|
||||
private Object defaultValue = null;
|
||||
|
||||
public Argument(String name, ArgumentType argumentsType) {
|
||||
this.name = name;
|
||||
this.argumentsType = argumentsType;
|
||||
}
|
||||
|
||||
public Argument optional(Object defaultValue) {
|
||||
optional = true;
|
||||
this.defaultValue = defaultValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public ArgumentType getArgumentsType() {
|
||||
return argumentsType;
|
||||
}
|
||||
|
||||
public boolean isOptional() {
|
||||
return optional;
|
||||
}
|
||||
|
||||
public Object getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public Argument suggest(Suggest suggest) {
|
||||
this.suggest = suggest;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Suggest getSuggest() {
|
||||
return suggest;
|
||||
}
|
||||
|
||||
public static Argument argument(String name, ArgumentType type) {
|
||||
return new Argument(name, type);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package com.io.yutian.elementoriginlib.command.argument;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class ArgumentType<T> {
|
||||
|
||||
private final String name;
|
||||
|
||||
private Predicate<String> predicate;
|
||||
private Function<String, T> function;
|
||||
|
||||
public ArgumentType(String name, Predicate<String> predicate, Function<String, T> function) {
|
||||
this.name = name;
|
||||
this.predicate = predicate;
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean test(String string) {
|
||||
return predicate.test(string);
|
||||
}
|
||||
|
||||
public T get(String t) {
|
||||
return function.apply(t);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package com.io.yutian.elementoriginlib.command.argument;
|
||||
|
||||
import com.io.yutian.elementoriginlib.util.StringUtil;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class ArgumentTypes {
|
||||
|
||||
public static final ArgumentType<String> STRING = new ArgumentType<>("string", (s) -> true, (s) -> s);
|
||||
|
||||
public static final ArgumentType<Integer> INTEGER = new ArgumentType<>("integer", StringUtil::isInt, Integer::parseInt);
|
||||
|
||||
public static final ArgumentType<Double> DOUBLE = new ArgumentType<>("double", StringUtil::isDouble, Double::parseDouble);
|
||||
|
||||
public static final ArgumentType<UUID> UUID = new ArgumentType<>("uuid", StringUtil::isUUID, java.util.UUID::fromString);
|
||||
|
||||
public static final ArgumentType<Boolean> BOOLEAN = new ArgumentType<>("boolean", StringUtil::isBoolean, Boolean::parseBoolean);
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package com.io.yutian.elementoriginlib.command.argument;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ArgumentValue {
|
||||
|
||||
private static final Map<Class<?>, Class<?>> PRIMITIVE_TO_WRAPPER = new HashMap<>();
|
||||
|
||||
static {
|
||||
PRIMITIVE_TO_WRAPPER.put(boolean.class, Boolean.class);
|
||||
PRIMITIVE_TO_WRAPPER.put(byte.class, Byte.class);
|
||||
PRIMITIVE_TO_WRAPPER.put(short.class, Short.class);
|
||||
PRIMITIVE_TO_WRAPPER.put(char.class, Character.class);
|
||||
PRIMITIVE_TO_WRAPPER.put(int.class, Integer.class);
|
||||
PRIMITIVE_TO_WRAPPER.put(long.class, Long.class);
|
||||
PRIMITIVE_TO_WRAPPER.put(float.class, Float.class);
|
||||
PRIMITIVE_TO_WRAPPER.put(double.class, Double.class);
|
||||
}
|
||||
|
||||
private Object value;
|
||||
|
||||
public ArgumentValue(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public <V> V get(Class<V> clazz) {
|
||||
if (PRIMITIVE_TO_WRAPPER.getOrDefault(clazz, clazz).isAssignableFrom(value.getClass())) {
|
||||
return (V) value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getString() {
|
||||
return (String) value;
|
||||
}
|
||||
|
||||
public int getInt() {
|
||||
return (Integer) value;
|
||||
}
|
||||
|
||||
public double getDouble() {
|
||||
return (Double) value;
|
||||
}
|
||||
|
||||
public boolean getBoolean() {
|
||||
return (Boolean) value;
|
||||
}
|
||||
|
||||
public UUID getUUID() {
|
||||
return (UUID) value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ArgumentValue{" +
|
||||
"value=" + value +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,341 @@
|
|||
package com.io.yutian.elementoriginlib.command.handler;
|
||||
|
||||
import com.io.yutian.elementoriginlib.command.*;
|
||||
import com.io.yutian.elementoriginlib.command.argument.Argument;
|
||||
import com.io.yutian.elementoriginlib.command.argument.ArgumentValue;
|
||||
import com.io.yutian.elementoriginlib.lang.Lang;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class CommandHandler implements CommandExecutor, TabCompleter {
|
||||
|
||||
private ICommandManager commandManager;
|
||||
|
||||
public CommandHandler(Plugin plugin, ICommandManager commandManager) {
|
||||
this.commandManager = commandManager;
|
||||
}
|
||||
|
||||
public void execute(CommandSender sender, String label, String[] args) {
|
||||
if (args.length == 0) {
|
||||
execute(sender, label, new String[]{"help", "1"});
|
||||
return;
|
||||
}
|
||||
List<ICommand> commands = commandManager.getCommands();
|
||||
String command = args[0];
|
||||
Stream<ICommand> stream = commands.stream().filter((c) -> c.getName().equalsIgnoreCase(command));
|
||||
Optional<ICommand> optional = stream.findFirst();
|
||||
if (!optional.isPresent()) {
|
||||
sender.sendMessage(Lang.get("command-unknown", command));
|
||||
return;
|
||||
}
|
||||
ICommand iCommand = optional.get();
|
||||
if (!iCommand.hasPermission(sender)) {
|
||||
sender.sendMessage(Lang.get("command-no-permission"));
|
||||
return;
|
||||
}
|
||||
List<CommandNode> commandNodes = iCommand.getCommandNodes();
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
stringBuilder.append(args[i]);
|
||||
if (i < args.length - 1) {
|
||||
stringBuilder.append(" ");
|
||||
}
|
||||
}
|
||||
String commandString = stringBuilder.toString();
|
||||
if (commandNodes.size() == 0) {
|
||||
Map<String, ArgumentValue> map = new HashMap<>();
|
||||
if (iCommand.getArguments().size() > 0) {
|
||||
int argSize = args.length - 1;
|
||||
List<Argument> arguments = iCommand.getArguments();
|
||||
int k = 0;
|
||||
if (arguments.get(arguments.size()-1).isOptional()) {
|
||||
k++;
|
||||
}
|
||||
if (argSize < arguments.size()-k) {
|
||||
sender.sendMessage(Lang.get("command-short-arg"));
|
||||
return;
|
||||
}
|
||||
for (int l = 0; l < arguments.size(); l++) {
|
||||
Argument a = arguments.get(l);
|
||||
int index = l + 1;
|
||||
if (index >= args.length) {
|
||||
break;
|
||||
}
|
||||
String arg = args[index];
|
||||
if (!a.getArgumentsType().test(arg)) {
|
||||
sender.sendMessage(Lang.get("command-unknown-arg", index+1, arg));
|
||||
return;
|
||||
}
|
||||
}
|
||||
map = parseArgumentValue(sender, arguments, args, 0);
|
||||
}
|
||||
iCommand.executes(new CommandContext(commandString, label, sender, map));
|
||||
return;
|
||||
}
|
||||
|
||||
int nodeSize = args.length - 1;
|
||||
|
||||
if (commandNodes.size() > 0 && nodeSize == 0) {
|
||||
if (!iCommand.emptyExecutes(sender)) {
|
||||
sender.sendMessage(Lang.get("command-short-arg"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
String mainNode = args[1];
|
||||
Stream<CommandNode> nodeStream = commandNodes.stream().filter((n) -> n.getName().equalsIgnoreCase(mainNode) || n.getAlias().contains(mainNode));
|
||||
Optional<CommandNode> nodeOptional = nodeStream.findFirst();
|
||||
if (!nodeOptional.isPresent()) {
|
||||
sender.sendMessage(Lang.get("command-unknown-arg", 2, mainNode));
|
||||
return;
|
||||
}
|
||||
CommandNode node = nodeOptional.get();
|
||||
|
||||
if (node.getChildrens().size() > 0) {
|
||||
checkClidren(commandString, label, sender, 1, args, node);
|
||||
} else {
|
||||
if (node.getCommand() != null) {
|
||||
Map<String, ArgumentValue> map = new HashMap<>();
|
||||
if (node.getArguments().size() > 0) {
|
||||
int argSize = args.length - 2;
|
||||
List<Argument> arguments = node.getArguments();
|
||||
int k = 0;
|
||||
if (arguments.get(arguments.size()-1).isOptional()) {
|
||||
k++;
|
||||
}
|
||||
if (argSize < arguments.size()-k) {
|
||||
sender.sendMessage(Lang.get("command-short-arg"));
|
||||
return;
|
||||
}
|
||||
for (int l = 0; l < arguments.size(); l++) {
|
||||
Argument a = arguments.get(l);
|
||||
int index = l + 1;
|
||||
if (index >= args.length) {
|
||||
break;
|
||||
}
|
||||
if (index+1 >= args.length) {
|
||||
break;
|
||||
}
|
||||
String arg = args[index+1];
|
||||
if (!a.getArgumentsType().test(arg)) {
|
||||
sender.sendMessage(Lang.get("command-error-arg", index+1, arg));
|
||||
return;
|
||||
}
|
||||
}
|
||||
map = parseArgumentValue(sender, node.getArguments(), args, 1);
|
||||
}
|
||||
node.getCommand().run(new CommandContext(commandString, label, sender, map));
|
||||
} else {
|
||||
sender.sendMessage(Lang.get("command-unknown-arg", 3, mainNode));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Map<String, ArgumentValue> parseArgumentValue(CommandSender commandSender, List<Argument> argumentList, String[] args, int i) {
|
||||
Map<String, ArgumentValue> map = new HashMap<>();
|
||||
List<Argument> arguments = argumentList;
|
||||
for (int l = 0; l < arguments.size(); l++) {
|
||||
Argument a = arguments.get(l);
|
||||
if (i+1+l >= args.length) {
|
||||
if (a.isOptional()) {
|
||||
map.put(a.getName(), new ArgumentValue(a.getDefaultValue()));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
String arg = args[i+1+l];
|
||||
if (!a.getArgumentsType().test(arg)) {
|
||||
continue;
|
||||
}
|
||||
ArgumentValue argumentValue = new ArgumentValue(a.getArgumentsType().get(arg));
|
||||
map.put(a.getName(), argumentValue);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private void checkClidren(String commandString, String label, CommandSender sender, int i, String[] args, CommandNode node) {
|
||||
i++;
|
||||
if (i >= args.length) {
|
||||
if (node.getCommand() == null) {
|
||||
sender.sendMessage(Lang.get("command-short-arg"));
|
||||
} else {
|
||||
node.getCommand().run(new CommandContext(commandString, label, sender, new HashMap<>()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
String s = args[i];
|
||||
Stream<CommandNode> nodeStream = node.getChildrens().stream().filter((n) -> n.getName().equalsIgnoreCase(s) || n.getAlias().contains(s));
|
||||
Optional<CommandNode> nodeOptional = nodeStream.findFirst();
|
||||
if (!nodeOptional.isPresent()) {
|
||||
sender.sendMessage(Lang.get("command-unknown-arg", i+1, s));
|
||||
return;
|
||||
}
|
||||
CommandNode node1 = nodeOptional.get();
|
||||
|
||||
if (node1.getChildrens().size() > 0) {
|
||||
checkClidren(commandString, label, sender, i, args, node1);
|
||||
} else {
|
||||
if (node1.getCommand() != null) {
|
||||
Map<String, ArgumentValue> map = new HashMap<>();
|
||||
if (node1.getArguments().size() > 0) {
|
||||
int argSize = args.length - i - 1;
|
||||
List<Argument> arguments = node1.getArguments();
|
||||
int k = 0;
|
||||
if (arguments.get(arguments.size()-1).isOptional()) {
|
||||
k++;
|
||||
}
|
||||
if (argSize < arguments.size()-k) {
|
||||
sender.sendMessage(Lang.get("command-short-arg"));
|
||||
return;
|
||||
}
|
||||
for (int l = 0; l < arguments.size(); l++) {
|
||||
Argument a = arguments.get(l);
|
||||
int index = i + l + 1;
|
||||
if (index >= args.length) {
|
||||
break;
|
||||
}
|
||||
String arg = args[index];
|
||||
if (!a.getArgumentsType().test(arg)) {
|
||||
sender.sendMessage(Lang.get("command-unknown-arg", index+1, arg));
|
||||
return;
|
||||
}
|
||||
}
|
||||
map = parseArgumentValue(sender, node1.getArguments(), args, i);
|
||||
}
|
||||
node1.getCommand().run(new CommandContext(commandString, label, sender, map));
|
||||
} else {
|
||||
sender.sendMessage(Lang.get("command-unknown-arg", i+1, s));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
execute(sender, label, args);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
||||
List<String> list = new ArrayList<>();
|
||||
int index = args.length;
|
||||
String arg = args[index-1];
|
||||
List<ICommand> commands = commandManager.getCommands();
|
||||
if (index == 1) {
|
||||
List<ICommand> commandList = commands.stream().filter((c)->c.getName().startsWith(arg)).collect(Collectors.toList());
|
||||
if (commandList.size() > 0) {
|
||||
commandList.forEach(c-> {
|
||||
if (c.hasPermission(sender)) {
|
||||
list.add(c.getName());
|
||||
}
|
||||
});
|
||||
return list;
|
||||
}
|
||||
commandList = commands.stream().filter((c)->c.getName().contains(arg)).collect(Collectors.toList());
|
||||
if (commandList.size() > 0) {
|
||||
commandList.forEach(c-> {
|
||||
if (c.hasPermission(sender)) {
|
||||
list.add(c.getName());
|
||||
}
|
||||
});
|
||||
return list;
|
||||
}
|
||||
} else {
|
||||
Optional<ICommand> iCommandOptional = commands.stream().filter((c)->c.getName().equalsIgnoreCase(args[0])).findFirst();
|
||||
if (!iCommandOptional.isPresent()) {
|
||||
return list;
|
||||
}
|
||||
ICommand iCommand = iCommandOptional.get();
|
||||
if (!iCommand.hasPermission(sender)) {
|
||||
return list;
|
||||
}
|
||||
if (iCommand instanceof ITabCompleter) {
|
||||
ITabCompleter tabCompleter = (ITabCompleter) iCommand;
|
||||
return tabCompleter.onTabComplete(sender, args, index-2, arg);
|
||||
} else {
|
||||
Map<Integer, List<String>> map = new HashMap<>();
|
||||
if (iCommand.getCommandNodes().size() > 0) {
|
||||
List<String> list1 = new ArrayList<>();
|
||||
for (CommandNode node : iCommand.getCommandNodes()) {
|
||||
list1.add(node.getName());
|
||||
list1.addAll(node.getAlias());
|
||||
if (index >= 2) {
|
||||
if (!node.getName().equalsIgnoreCase(args[1])) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (node.getChildrens().size() > 0) {
|
||||
getTabComplete(node, 2, map);
|
||||
} else if (node.getArguments().size() > 0) {
|
||||
List<Argument> arguments = node.getArguments();
|
||||
for (int l = 0; l < arguments.size(); l++) {
|
||||
Argument argument = arguments.get(l);
|
||||
if (argument.getSuggest() != null) {
|
||||
map.put(2+l+1, argument.getSuggest().getSuggest());
|
||||
continue;
|
||||
}
|
||||
map.put(2+l+1, Arrays.asList("<"+argument.getName()+">"));
|
||||
}
|
||||
}
|
||||
}
|
||||
map.put(2, list1);
|
||||
return preseSuggest(map.getOrDefault(index, list), arg);
|
||||
} else if (iCommand.getArguments().size() > 0) {
|
||||
List<Argument> arguments = iCommand.getArguments();
|
||||
for (int l = 0; l < arguments.size(); l++) {
|
||||
Argument argument = arguments.get(l);
|
||||
if (argument.getSuggest() != null) {
|
||||
map.put(1+l+1, argument.getSuggest().getSuggest());
|
||||
continue;
|
||||
}
|
||||
map.put(1+l+1, Arrays.asList("<"+argument.getName()+">"));
|
||||
}
|
||||
return preseSuggest(map.getOrDefault(index, list), arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
return preseSuggest(list, arg);
|
||||
}
|
||||
|
||||
public static List<String> preseSuggest(List<String> list, String arg) {
|
||||
List<String> newList = new ArrayList<>();
|
||||
List<String> list1 = list.stream().filter((c)->c.startsWith(arg)||c.toLowerCase().startsWith(arg.toLowerCase())).collect(Collectors.toList());
|
||||
List<String> list2 = list.stream().filter((c)->c.contains(arg)||c.toLowerCase().contains(arg.toLowerCase())).collect(Collectors.toList());
|
||||
List<String> list3 = list.stream().filter((c)->c.equalsIgnoreCase(arg)|| c.equalsIgnoreCase(arg)).collect(Collectors.toList());
|
||||
newList.addAll(list1);
|
||||
newList.addAll(list2);
|
||||
newList.addAll(list3);
|
||||
return newList;
|
||||
}
|
||||
|
||||
private void getTabComplete(CommandNode node, int i, Map<Integer, List<String>> map) {
|
||||
i++;
|
||||
List<String> list = map.getOrDefault(i, new ArrayList<>());
|
||||
for (CommandNode c : node.getChildrens()) {
|
||||
list.add(c.getName());
|
||||
if (c.getChildrens().size() > 0) {
|
||||
getTabComplete(c, i, map);
|
||||
} else if (c.getArguments().size() > 0) {
|
||||
List<Argument> arguments = c.getArguments();
|
||||
for (int l = 0; l < arguments.size(); l++) {
|
||||
Argument argument = arguments.get(l);
|
||||
if (argument.getSuggest() != null) {
|
||||
map.put(i+l+1, argument.getSuggest().getSuggest());
|
||||
continue;
|
||||
}
|
||||
map.put(i+l+1, Arrays.asList("<"+argument.getName()+">"));
|
||||
}
|
||||
}
|
||||
}
|
||||
map.put(i, list);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
package com.io.yutian.elementoriginlib.command.list;
|
||||
|
||||
import com.io.yutian.elementoriginlib.command.CommandContext;
|
||||
import com.io.yutian.elementoriginlib.command.CommandNode;
|
||||
import com.io.yutian.elementoriginlib.command.ICommand;
|
||||
import com.io.yutian.elementoriginlib.command.ICommandManager;
|
||||
import com.io.yutian.elementoriginlib.command.argument.Argument;
|
||||
import com.io.yutian.elementoriginlib.command.argument.ArgumentTypes;
|
||||
import com.io.yutian.elementoriginlib.lang.Lang;
|
||||
import com.io.yutian.elementoriginlib.util.ComponentBuilder;
|
||||
import com.io.yutian.elementoriginlib.list.PageList;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class CommandHelp extends ICommand {
|
||||
|
||||
private ICommandManager commandManager;
|
||||
@Nullable
|
||||
private String alias;
|
||||
|
||||
public CommandHelp(ICommandManager commandManager) {
|
||||
this(commandManager, null);
|
||||
}
|
||||
|
||||
public CommandHelp(ICommandManager commandManager, String alias) {
|
||||
super("help");
|
||||
this.commandManager = commandManager;
|
||||
this.alias = alias;
|
||||
addArgument(Argument.argument("page", ArgumentTypes.INTEGER).optional(1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(CommandSender sender) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executes(CommandContext commandContext) {
|
||||
String commandAlias = alias != null ? alias : commandContext.getLabel();
|
||||
CommandSender sender = commandContext.getSender();
|
||||
int page = commandContext.getArgumentsValue("page").getInt();
|
||||
if (page <= 0) {
|
||||
sender.sendMessage(Lang.get("command.help.page-error"));
|
||||
return;
|
||||
}
|
||||
List<ICommand> commands = commandManager.getCommands();
|
||||
Stream<ICommand> stream = commands.stream().filter((c) -> c.hasPermission(sender));
|
||||
List<ICommand> list = stream.collect(Collectors.toList());
|
||||
PageList<ICommand> pageList = new PageList<>(list, 8);
|
||||
if (page > pageList.size()) {
|
||||
sender.sendMessage(Lang.get("command.help.page-error"));
|
||||
return;
|
||||
}
|
||||
sender.sendMessage(" ");
|
||||
List<ICommand> commandList = pageList.getList(page);
|
||||
sender.sendMessage("§7======[ §e§l"+commandManager.getName()+" §7]======");
|
||||
for (ICommand command : commandList) {
|
||||
StringBuilder stringBuilder = new StringBuilder("§6/"+commandAlias+" "+command.getName());
|
||||
stringBuilder.append("§f");
|
||||
if (command.getCommandNodes().size() > 0) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(" [");
|
||||
int i = 0;
|
||||
for (CommandNode node : command.getCommandNodes()) {
|
||||
sb.append(node.getName());
|
||||
if (i + 1 < command.getCommandNodes().size()) {
|
||||
sb.append("/");
|
||||
}
|
||||
i++;
|
||||
}
|
||||
sb.append("]");
|
||||
stringBuilder.append(sb);
|
||||
} else {
|
||||
for (Argument argument : command.getArguments()) {
|
||||
stringBuilder.append(" ");
|
||||
stringBuilder.append("<"+argument.getName()+">");
|
||||
}
|
||||
}
|
||||
if (command.getDescription() != null) {
|
||||
stringBuilder.append(" ");
|
||||
stringBuilder.append("§7- §f"+command.getDescription());
|
||||
}
|
||||
sender.sendMessage(stringBuilder.toString());
|
||||
}
|
||||
ComponentBuilder componentBuilder = new ComponentBuilder();
|
||||
boolean hasUpPage = page > 1;
|
||||
boolean hasNextPage = page < pageList.size();
|
||||
componentBuilder.add("§7=====");
|
||||
if (hasUpPage) {
|
||||
componentBuilder.add(" §7["+getColor(true)+"◀§7] ", ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND, "/"+commandAlias+" help "+(page-1)), HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT, Component.text("§f上一页")));
|
||||
} else {
|
||||
componentBuilder.add(" §7["+getColor(false)+"◀§7] ");
|
||||
}
|
||||
componentBuilder.add("§7====");
|
||||
componentBuilder.add("(§a"+page+"§f/§e"+pageList.size()+"§7)");
|
||||
componentBuilder.add("§7====");
|
||||
if (hasNextPage) {
|
||||
componentBuilder.add(" §7["+getColor(true)+"▶§7] ", ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND, "/"+commandAlias+" help "+(page+1)), HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT, Component.text("§f下一页")));
|
||||
} else {
|
||||
componentBuilder.add(" §7["+getColor(false)+"▶§7] ");
|
||||
}
|
||||
componentBuilder.add("§7=====");
|
||||
sender.sendMessage(componentBuilder.build());
|
||||
}
|
||||
|
||||
private String getColor(boolean hasPage) {
|
||||
return hasPage ? "§a" : "§c";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.io.yutian.elementoriginlib.exception;
|
||||
|
||||
public class SerializeException extends RuntimeException {
|
||||
|
||||
public SerializeException(Class clazz, Throwable cause) {
|
||||
super(clazz.toString());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.io.yutian.elementoriginlib.expiringmap;
|
||||
|
||||
/**
|
||||
* Loads entries on demand.
|
||||
*
|
||||
* @param <K> Key type
|
||||
* @param <V> Value type
|
||||
*/
|
||||
public interface EntryLoader<K, V> {
|
||||
/**
|
||||
* Called to load a new value for the {@code key} into an expiring map.
|
||||
*
|
||||
* @param key to load a value for
|
||||
* @return new value to load
|
||||
*/
|
||||
V load(K key);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.io.yutian.elementoriginlib.expiringmap;
|
||||
|
||||
/**
|
||||
* A listener for expired object events.
|
||||
*
|
||||
* @param <K> Key type
|
||||
* @param <V> Value type
|
||||
*/
|
||||
public interface ExpirationListener<K, V> {
|
||||
/**
|
||||
* Called when a map entry expires.
|
||||
*
|
||||
* @param key Expired key
|
||||
* @param value Expired value
|
||||
*/
|
||||
void expired(K key, V value);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.io.yutian.elementoriginlib.expiringmap;
|
||||
|
||||
/**
|
||||
* Determines how ExpiringMap entries should be expired.
|
||||
*/
|
||||
public enum ExpirationPolicy {
|
||||
/** Expires entries based on when they were last accessed */
|
||||
ACCESSED,
|
||||
/** Expires entries based on when they were created */
|
||||
CREATED;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.io.yutian.elementoriginlib.expiringmap;
|
||||
|
||||
/**
|
||||
* Loads entries on demand, with control over each value's expiry duration (i.e. variable expiration).
|
||||
*
|
||||
* @param <K> Key type
|
||||
* @param <V> Value type
|
||||
*/
|
||||
public interface ExpiringEntryLoader<K, V> {
|
||||
/**
|
||||
* Called to load a new value for the {@code key} into an expiring map.
|
||||
*
|
||||
* @param key to load a value for
|
||||
* @return contains new value to load along with its expiry duration
|
||||
*/
|
||||
ExpiringValue<V> load(K key);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,122 @@
|
|||
package com.io.yutian.elementoriginlib.expiringmap;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* A value which should be stored in an {@link ExpiringMap} with optional control over its expiration.
|
||||
*
|
||||
* @param <V> the type of value being stored
|
||||
*/
|
||||
public final class ExpiringValue<V> {
|
||||
private static final long UNSET_DURATION = -1L;
|
||||
private final V value;
|
||||
private final ExpirationPolicy expirationPolicy;
|
||||
private final long duration;
|
||||
private final TimeUnit timeUnit;
|
||||
|
||||
/**
|
||||
* Creates an ExpiringValue to be stored in an {@link ExpiringMap}. The map's default values for
|
||||
* {@link ExpirationPolicy expiration policy} and {@link ExpiringMap#getExpiration()} expiration} will be used.
|
||||
*
|
||||
* @param value the value to store
|
||||
* @see ExpiringMap#put(Object, Object)
|
||||
*/
|
||||
public ExpiringValue(V value) {
|
||||
this(value, UNSET_DURATION, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ExpiringValue to be stored in an {@link ExpiringMap}. The map's default
|
||||
* {@link ExpiringMap#getExpiration()} expiration} will be used.
|
||||
*
|
||||
* @param value the value to store
|
||||
* @param expirationPolicy the expiration policy for the value
|
||||
* @see ExpiringMap#put(Object, Object, ExpirationPolicy)
|
||||
*/
|
||||
public ExpiringValue(V value, ExpirationPolicy expirationPolicy) {
|
||||
this(value, UNSET_DURATION, null, expirationPolicy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ExpiringValue to be stored in an {@link ExpiringMap}. The map's default {@link ExpirationPolicy
|
||||
* expiration policy} will be used.
|
||||
*
|
||||
* @param value the value to store
|
||||
* @param duration the length of time after an entry is created that it should be removed
|
||||
* @param timeUnit the unit that {@code duration} is expressed in
|
||||
* @see ExpiringMap#put(Object, Object, long, TimeUnit)
|
||||
* @throws NullPointerException on null timeUnit
|
||||
*/
|
||||
public ExpiringValue(V value, long duration, TimeUnit timeUnit) {
|
||||
this(value, duration, timeUnit, null);
|
||||
if (timeUnit == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ExpiringValue to be stored in an {@link ExpiringMap}.
|
||||
*
|
||||
* @param value the value to store
|
||||
* @param duration the length of time after an entry is created that it should be removed
|
||||
* @param timeUnit the unit that {@code duration} is expressed in
|
||||
* @param expirationPolicy the expiration policy for the value
|
||||
* @see ExpiringMap#put(Object, Object, ExpirationPolicy, long, TimeUnit)
|
||||
* @throws NullPointerException on null timeUnit
|
||||
*/
|
||||
public ExpiringValue(V value, ExpirationPolicy expirationPolicy, long duration, TimeUnit timeUnit) {
|
||||
this(value, duration, timeUnit, expirationPolicy);
|
||||
if (timeUnit == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
}
|
||||
|
||||
private ExpiringValue(V value, long duration, TimeUnit timeUnit, ExpirationPolicy expirationPolicy) {
|
||||
this.value = value;
|
||||
this.expirationPolicy = expirationPolicy;
|
||||
this.duration = duration;
|
||||
this.timeUnit = timeUnit;
|
||||
}
|
||||
|
||||
public V getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public ExpirationPolicy getExpirationPolicy() {
|
||||
return expirationPolicy;
|
||||
}
|
||||
|
||||
public long getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public TimeUnit getTimeUnit() {
|
||||
return timeUnit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value != null ? value.hashCode() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ExpiringValue<?> that = (ExpiringValue<?>) o;
|
||||
return !(value != null ? !value.equals(that.value) : that.value != null)
|
||||
&& expirationPolicy == that.expirationPolicy && duration == that.duration && timeUnit == that.timeUnit;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ExpiringValue{" + "value=" + value + ", expirationPolicy=" + expirationPolicy + ", duration=" + duration
|
||||
+ ", timeUnit=" + timeUnit + '}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package com.io.yutian.elementoriginlib.expiringmap.internal;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* @author Jonathan Halterman
|
||||
*/
|
||||
public final class Assert {
|
||||
private Assert() {
|
||||
}
|
||||
|
||||
public static <T> T notNull(T reference, String parameterName) {
|
||||
if (reference == null)
|
||||
throw new NullPointerException(parameterName + " cannot be null");
|
||||
return reference;
|
||||
}
|
||||
|
||||
public static void operation(boolean condition, String message) {
|
||||
if (!condition)
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
public static void state(boolean expression, String errorMessageFormat, Object... args) {
|
||||
if (!expression)
|
||||
throw new IllegalStateException(String.format(errorMessageFormat, args));
|
||||
}
|
||||
|
||||
public static void element(Object element, Object key) {
|
||||
if (element == null)
|
||||
throw new NoSuchElementException(key.toString());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.io.yutian.elementoriginlib.expiringmap.internal;
|
||||
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Named thread factory.
|
||||
*/
|
||||
public class NamedThreadFactory implements ThreadFactory {
|
||||
private final AtomicInteger threadNumber = new AtomicInteger(1);
|
||||
private final String nameFormat;
|
||||
|
||||
/**
|
||||
* Creates a thread factory that names threads according to the {@code nameFormat} by supplying a
|
||||
* single argument to the format representing the thread number.
|
||||
*/
|
||||
public NamedThreadFactory(String nameFormat) {
|
||||
this.nameFormat = nameFormat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread thread = new Thread(r, String.format(nameFormat, threadNumber.getAndIncrement()));
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
}
|
||||
}
|
133
src/main/java/com/io/yutian/elementoriginlib/gui/Gui.java
Normal file
133
src/main/java/com/io/yutian/elementoriginlib/gui/Gui.java
Normal file
|
@ -0,0 +1,133 @@
|
|||
package com.io.yutian.elementoriginlib.gui;
|
||||
|
||||
import com.io.yutian.elementoriginlib.ElementOriginLib;
|
||||
import com.io.yutian.elementoriginlib.gui.button.Button;
|
||||
import com.io.yutian.elementoriginlib.gui.button.ClickType;
|
||||
import com.io.yutian.elementoriginlib.gui.button.ItemButton;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.InventoryAction;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Gui extends IGui {
|
||||
|
||||
private Map<Integer, Button> buttons = new HashMap<>();
|
||||
|
||||
public Gui(Player player, Component title, int size) {
|
||||
super(player, title, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handler(Player player, int slot, InventoryClickEvent event) {
|
||||
if (buttons.containsKey(slot)) {
|
||||
Button button = buttons.get(slot);
|
||||
if (button == null) {
|
||||
if (slot < inventory.getSize()) {
|
||||
event.setCancelled(true);
|
||||
} else {
|
||||
if (event.getAction().equals(InventoryAction.MOVE_TO_OTHER_INVENTORY)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
event.setCancelled(true);
|
||||
clickButton(event, slot, button);
|
||||
if (button.isPlaySound()) {
|
||||
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1.0f, 1.0f);
|
||||
}
|
||||
InventoryAction action = event.getAction();
|
||||
ClickType clickType = ClickType.LEFT_CLICK;
|
||||
if (action.equals(InventoryAction.PICKUP_ALL)) {
|
||||
clickType = ClickType.LEFT_CLICK;
|
||||
} else if (action.equals(InventoryAction.PICKUP_HALF)) {
|
||||
clickType = ClickType.RIGHT_CLICK;
|
||||
} else if (action.equals(InventoryAction.MOVE_TO_OTHER_INVENTORY)) {
|
||||
clickType = ClickType.SHIFT_CLICK;
|
||||
}
|
||||
if (button.getClickConsumer() != null) {
|
||||
button.getClickConsumer().accept(player, clickType);
|
||||
}
|
||||
} else {
|
||||
if (slot < inventory.getSize()) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addButton(int index, Button button) {
|
||||
buttons.put(index, button);
|
||||
}
|
||||
|
||||
public Button getButton(int index) {
|
||||
return buttons.getOrDefault(index, null);
|
||||
}
|
||||
|
||||
public final void initButton(int index) {
|
||||
inventory.setItem(index, null);
|
||||
Button button = getButton(index);
|
||||
if (button == null) {
|
||||
return;
|
||||
}
|
||||
if (button.isAsynchronous()) {
|
||||
ElementOriginLib.inst().getServer().getScheduler().runTaskAsynchronously(ElementOriginLib.inst(), ()->{
|
||||
if (button instanceof ItemButton itemButton) {
|
||||
if (itemButton.getItem() != null) {
|
||||
inventory.setItem(index, itemButton.getItem());
|
||||
return;
|
||||
}
|
||||
}
|
||||
inventory.setItem(index, button.getItemStack());
|
||||
});
|
||||
} else {
|
||||
if (button instanceof ItemButton itemButton) {
|
||||
if (itemButton.getItem() != null) {
|
||||
inventory.setItem(index, itemButton.getItem());
|
||||
return;
|
||||
}
|
||||
}
|
||||
inventory.setItem(index, button.getItemStack());
|
||||
}
|
||||
}
|
||||
|
||||
public final void initButton() {
|
||||
for (int i = 0; i < inventory.getSize(); i++) {
|
||||
inventory.setItem(i, null);
|
||||
}
|
||||
for (Map.Entry<Integer, Button> entry : buttons.entrySet()) {
|
||||
Button button = entry.getValue();
|
||||
if (button.isAsynchronous()) {
|
||||
ElementOriginLib.inst().getServer().getScheduler().runTaskAsynchronously(ElementOriginLib.inst(), ()->{
|
||||
if (button instanceof ItemButton itemButton) {
|
||||
if (itemButton.getItem() != null) {
|
||||
inventory.setItem(entry.getKey(), itemButton.getItem());
|
||||
return;
|
||||
}
|
||||
}
|
||||
inventory.setItem(entry.getKey(), button.getItemStack());
|
||||
});
|
||||
} else {
|
||||
if (button instanceof ItemButton itemButton) {
|
||||
if (itemButton.getItem() != null) {
|
||||
inventory.setItem(entry.getKey(), itemButton.getItem());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
inventory.setItem(entry.getKey(), button.getItemStack());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Map<Integer, Button> getButtons() {
|
||||
return buttons;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package com.io.yutian.elementoriginlib.gui;
|
||||
|
||||
import com.io.yutian.elementoriginlib.listener.IListener;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.inventory.InventoryAction;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class GuiHandler extends IListener {
|
||||
|
||||
public GuiHandler(Plugin plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onInventoryClick(InventoryClickEvent event) {
|
||||
if (event.getInventory().getHolder() == null) {
|
||||
return;
|
||||
}
|
||||
Player player = (Player) event.getWhoClicked();
|
||||
InventoryHolder holder = event.getInventory().getHolder();
|
||||
if (holder instanceof IGui iGui) {
|
||||
if (event.getClickedInventory() != event.getInventory()) {
|
||||
if (event.getAction().equals(InventoryAction.MOVE_TO_OTHER_INVENTORY) || event.getAction().equals(InventoryAction.COLLECT_TO_CURSOR)) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (event.getAction().equals(InventoryAction.HOTBAR_SWAP) || event.getAction().equals(InventoryAction.HOTBAR_MOVE_AND_READD)) {
|
||||
event.setCancelled(true);
|
||||
player.getInventory().setItemInOffHand(player.getInventory().getItemInOffHand());
|
||||
return;
|
||||
}
|
||||
int slot = event.getRawSlot();
|
||||
iGui.handler(player, slot, event);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryDrag(InventoryDragEvent event) {
|
||||
if (event.getInventory().getHolder() != null) {
|
||||
InventoryHolder inventoryHolder = event.getInventory().getHolder();
|
||||
if (inventoryHolder instanceof IGui) {
|
||||
if (inventoryHolder instanceof IGuiDrag iGuiDrag) {
|
||||
iGuiDrag.onInventoryDrag(event);
|
||||
} else {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryClose(InventoryCloseEvent event) {
|
||||
if (event.getInventory().getHolder() != null) {
|
||||
InventoryHolder inventoryHolder = event.getInventory().getHolder();
|
||||
if (inventoryHolder instanceof IGui iGui) {
|
||||
iGui.close(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
142
src/main/java/com/io/yutian/elementoriginlib/gui/IGui.java
Normal file
142
src/main/java/com/io/yutian/elementoriginlib/gui/IGui.java
Normal file
|
@ -0,0 +1,142 @@
|
|||
package com.io.yutian.elementoriginlib.gui;
|
||||
|
||||
import com.io.yutian.elementoriginlib.gui.button.Button;
|
||||
import com.io.yutian.elementoriginlib.gui.button.ButtonHandler;
|
||||
import com.io.yutian.elementoriginlib.gui.button.ItemButton;
|
||||
import com.io.yutian.elementoriginlib.gui.button.ItemSlotButton;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public abstract class IGui implements InventoryHolder {
|
||||
|
||||
public Inventory inventory;
|
||||
public Player player;
|
||||
|
||||
private Component title;
|
||||
private int size;
|
||||
|
||||
public IGui(Player player, Component title, int size) {
|
||||
this.inventory = Bukkit.createInventory(this, size, title);
|
||||
this.title = title;
|
||||
this.size = size;
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public abstract void init();
|
||||
|
||||
public abstract void handler(Player player, int slot, InventoryClickEvent event);
|
||||
|
||||
public void close(InventoryCloseEvent event) {
|
||||
}
|
||||
|
||||
public void open() {
|
||||
player.openInventory(inventory);
|
||||
}
|
||||
|
||||
public void clickButton(InventoryClickEvent event, int slot, Button button) {
|
||||
if (button instanceof ItemButton itemButton) {
|
||||
ItemStack itemStack = event.getCurrentItem();
|
||||
ItemStack item = event.getCursor();
|
||||
if (itemButton.isItem(itemStack)) {
|
||||
if (item != null & !item.getType().equals(Material.AIR)) {
|
||||
if (itemButton.getPutPredicate() != null && !itemButton.getPutPredicate().test(player, item)) {
|
||||
return;
|
||||
}
|
||||
if (itemButton.getClickItemConsumer() != null) {
|
||||
itemButton.getClickItemConsumer().accept(player, item);
|
||||
}
|
||||
player.setItemOnCursor(null);
|
||||
if (itemButton.getPutItemFunction() != null) {
|
||||
ItemStack itemStack1 = itemButton.getPutItemFunction().apply(item);
|
||||
itemButton.setItem(itemStack1);
|
||||
inventory.setItem(slot, itemStack1);
|
||||
} else {
|
||||
itemButton.setItem(item);
|
||||
inventory.setItem(slot, item);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (item == null || item.getType().equals(Material.AIR)) {
|
||||
if (itemButton.getClickItemConsumer() != null) {
|
||||
itemButton.getClickItemConsumer().accept(player, item);
|
||||
}
|
||||
player.setItemOnCursor(itemStack);
|
||||
itemButton.setItem(null);
|
||||
inventory.setItem(slot, button.getItemStack());
|
||||
} else {
|
||||
if (itemButton.getPutPredicate() != null && !itemButton.getPutPredicate().test(player, item)) {
|
||||
return;
|
||||
}
|
||||
player.setItemOnCursor(itemStack);
|
||||
if (itemButton.getPutItemFunction() != null) {
|
||||
ItemStack itemStack1 = itemButton.getPutItemFunction().apply(item);
|
||||
if (itemButton.getClickItemConsumer() != null) {
|
||||
itemButton.getClickItemConsumer().accept(player, itemStack1);
|
||||
}
|
||||
itemButton.setItem(itemStack1);
|
||||
inventory.setItem(slot, itemStack1);
|
||||
} else {
|
||||
if (itemButton.getClickItemConsumer() != null) {
|
||||
itemButton.getClickItemConsumer().accept(player, item);
|
||||
}
|
||||
itemButton.setItem(item);
|
||||
inventory.setItem(slot, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (button instanceof ItemSlotButton itemSlotButton) {
|
||||
ItemStack itemStack = event.getCurrentItem();
|
||||
ItemStack item = event.getCursor();
|
||||
if (item == null || item.getType().equals(Material.AIR)) {
|
||||
if (itemStack == null || itemStack.getType().equals(Material.AIR)) {
|
||||
return;
|
||||
}
|
||||
inventory.setItem(slot, null);
|
||||
itemSlotButton.setItemStack(null);
|
||||
player.setItemOnCursor(itemStack);
|
||||
if (itemSlotButton.getPickItemFunction() != null) {
|
||||
itemSlotButton.getPickItemFunction().accept(itemStack);
|
||||
}
|
||||
} else {
|
||||
if (itemStack == null || itemStack.getType().equals(Material.AIR)) {
|
||||
if (!itemSlotButton.isCanPut()) {
|
||||
return;
|
||||
}
|
||||
player.setItemOnCursor(null);
|
||||
itemSlotButton.setItemStack(item);
|
||||
inventory.setItem(slot, item);
|
||||
if (itemSlotButton.getPutItemFunction() != null) {
|
||||
itemSlotButton.getPutItemFunction().accept(item);
|
||||
}
|
||||
} else {
|
||||
if (!itemSlotButton.isCanPut()) {
|
||||
return;
|
||||
}
|
||||
player.setItemOnCursor(itemStack);
|
||||
itemSlotButton.setItemStack(item);
|
||||
inventory.setItem(slot, item);
|
||||
if (itemSlotButton.getPutItemFunction() != null) {
|
||||
itemSlotButton.getPutItemFunction().accept(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (button instanceof ButtonHandler buttonHandler) {
|
||||
buttonHandler.handler(event, slot, button);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Inventory getInventory() {
|
||||
return inventory;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.io.yutian.elementoriginlib.gui;
|
||||
|
||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||
|
||||
public interface IGuiDrag {
|
||||
|
||||
void onInventoryDrag(InventoryDragEvent event);
|
||||
|
||||
}
|
174
src/main/java/com/io/yutian/elementoriginlib/gui/PageGui.java
Normal file
174
src/main/java/com/io/yutian/elementoriginlib/gui/PageGui.java
Normal file
|
@ -0,0 +1,174 @@
|
|||
package com.io.yutian.elementoriginlib.gui;
|
||||
|
||||
import com.io.yutian.elementoriginlib.ElementOriginLib;
|
||||
import com.io.yutian.elementoriginlib.gui.button.Button;
|
||||
import com.io.yutian.elementoriginlib.gui.button.ClickType;
|
||||
import com.io.yutian.elementoriginlib.gui.button.ItemButton;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.InventoryAction;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class PageGui extends IGui {
|
||||
|
||||
private int page = 1;
|
||||
private int maxPage;
|
||||
|
||||
private Map<Integer, Page> pages = new HashMap<>();
|
||||
|
||||
public PageGui(Player player, Component title, int size, int maxPage) {
|
||||
super(player, title, size);
|
||||
this.maxPage = maxPage;
|
||||
}
|
||||
|
||||
public void initButton() {
|
||||
initButton(this.page);
|
||||
}
|
||||
|
||||
public void initButton(int page) {
|
||||
if (page > pages.size()) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < inventory.getSize(); i++) {
|
||||
inventory.setItem(i, null);
|
||||
}
|
||||
if (pages.containsKey(page)) {
|
||||
Page page1 = pages.get(page);
|
||||
for (Map.Entry<Integer, Button> entry : page1.buttons.entrySet()) {
|
||||
Button button = entry.getValue();
|
||||
if (button.isAsynchronous()) {
|
||||
ElementOriginLib.inst().getServer().getScheduler().runTaskAsynchronously(ElementOriginLib.inst(), ()->{
|
||||
if (button instanceof ItemButton itemButton) {
|
||||
if (itemButton.getItem() != null) {
|
||||
inventory.setItem(entry.getKey(), itemButton.getItem());
|
||||
return;
|
||||
}
|
||||
}
|
||||
inventory.setItem(entry.getKey(), button.getItemStack());
|
||||
});
|
||||
} else {
|
||||
if (button instanceof ItemButton itemButton) {
|
||||
if (itemButton.getItem() != null) {
|
||||
inventory.setItem(entry.getKey(), itemButton.getItem());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
inventory.setItem(entry.getKey(), button.getItemStack());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handler(Player player, int slot, InventoryClickEvent event) {
|
||||
if (pages.containsKey(page)) {
|
||||
Page page1 = getPage(page);
|
||||
Button button = page1.getButton(slot);
|
||||
if (button == null) {
|
||||
if (slot < inventory.getSize()) {
|
||||
event.setCancelled(true);
|
||||
} else {
|
||||
if (event.getAction().equals(InventoryAction.MOVE_TO_OTHER_INVENTORY)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
event.setCancelled(true);
|
||||
clickButton(event, slot, button);
|
||||
if (button.isPlaySound()) {
|
||||
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1.0f, 1.0f);
|
||||
}
|
||||
InventoryAction action = event.getAction();
|
||||
ClickType clickType = ClickType.LEFT_CLICK;
|
||||
if (action.equals(InventoryAction.PICKUP_ALL)) {
|
||||
clickType = ClickType.LEFT_CLICK;
|
||||
} else if (action.equals(InventoryAction.PICKUP_HALF)) {
|
||||
clickType = ClickType.RIGHT_CLICK;
|
||||
} else if (action.equals(InventoryAction.MOVE_TO_OTHER_INVENTORY)) {
|
||||
clickType = ClickType.SHIFT_CLICK;
|
||||
}
|
||||
if (button.getClickConsumer() != null) {
|
||||
button.getClickConsumer().accept(player, clickType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Page getPage(int page) {
|
||||
if (page <= 0 || page > maxPage) {
|
||||
return null;
|
||||
}
|
||||
if (!pages.containsKey(page)) {
|
||||
pages.put(page, new Page());
|
||||
}
|
||||
return pages.get(page);
|
||||
}
|
||||
|
||||
public void setPage(int page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
public void next() {
|
||||
if (page >= maxPage) {
|
||||
return;
|
||||
}
|
||||
this.page ++;
|
||||
initButton();
|
||||
}
|
||||
|
||||
public void up() {
|
||||
if (page <= 1) {
|
||||
return;
|
||||
}
|
||||
this.page --;
|
||||
initButton();
|
||||
}
|
||||
|
||||
public int getPage() {
|
||||
return page;
|
||||
}
|
||||
|
||||
public int getMaxPage() {
|
||||
return maxPage;
|
||||
}
|
||||
|
||||
public void setMaxPage(int maxPage) {
|
||||
this.maxPage = maxPage;
|
||||
}
|
||||
|
||||
public void addButton(int page, int index, Button button) {
|
||||
Page page1 = pages.getOrDefault(page, new Page());
|
||||
page1.buttons.put(index, button);
|
||||
pages.put(page, page1);
|
||||
}
|
||||
|
||||
public static class Page {
|
||||
|
||||
private Map<Integer, Button> buttons = new HashMap<>();
|
||||
|
||||
public Page() {
|
||||
}
|
||||
|
||||
public void addButton(int index, Button button) {
|
||||
buttons.put(index, button);
|
||||
}
|
||||
|
||||
public Button getButton(int index) {
|
||||
return buttons.getOrDefault(index, null);
|
||||
}
|
||||
|
||||
public Map<Integer, Button> getButtons() {
|
||||
return buttons;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.io.yutian.elementoriginlib.gui.button;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public class Button {
|
||||
|
||||
private ItemStack itemStack;
|
||||
|
||||
private BiConsumer<Player, ClickType> clickConsumer;
|
||||
|
||||
private boolean asynchronous = false;
|
||||
private boolean playSound = true;
|
||||
|
||||
public Button(ItemStack itemStack) {
|
||||
this.itemStack = itemStack;
|
||||
}
|
||||
|
||||
public void setItemStack(ItemStack itemStack) {
|
||||
this.itemStack = itemStack;
|
||||
}
|
||||
|
||||
public Button click(BiConsumer<Player, ClickType> consumer) {
|
||||
this.clickConsumer = consumer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Button asyn() {
|
||||
this.asynchronous = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Button noSound() {
|
||||
this.playSound = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemStack getItemStack() {
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
public BiConsumer<Player, ClickType> getClickConsumer() {
|
||||
return clickConsumer;
|
||||
}
|
||||
|
||||
public boolean isAsynchronous() {
|
||||
return asynchronous;
|
||||
}
|
||||
|
||||
public boolean isPlaySound() {
|
||||
return playSound;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.io.yutian.elementoriginlib.gui.button;
|
||||
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
|
||||
public interface ButtonHandler {
|
||||
|
||||
void handler(InventoryClickEvent event, int slot, Button button);
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.io.yutian.elementoriginlib.gui.button;
|
||||
|
||||
public enum ClickType {
|
||||
|
||||
LEFT_CLICK,
|
||||
RIGHT_CLICK,
|
||||
SHIFT_CLICK
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package com.io.yutian.elementoriginlib.gui.button;
|
||||
|
||||
import com.io.yutian.elementoriginlib.nbt.NBTItem;
|
||||
import com.io.yutian.elementoriginlib.nbt.NBTString;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class ItemButton extends Button {
|
||||
|
||||
private BiConsumer<Player, ItemStack> clickItemConsumer;
|
||||
|
||||
private Function<ItemStack, ItemStack> putItemFunction;
|
||||
private BiPredicate<Player, ItemStack> putPredicate;
|
||||
|
||||
private ItemStack item;
|
||||
|
||||
public ItemButton(ItemStack itemStack) {
|
||||
super(itemStack);
|
||||
NBTItem nbtItem = new NBTItem(itemStack);
|
||||
nbtItem.editTag((nbtCompound -> {
|
||||
nbtCompound.putString("gui_meta", "item_button");
|
||||
}));
|
||||
setItemStack(nbtItem.getItemStack());
|
||||
}
|
||||
|
||||
public ItemButton setItem(ItemStack item) {
|
||||
this.item = item;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemStack getItem() {
|
||||
return item;
|
||||
}
|
||||
|
||||
public ItemButton itemPredicate(BiPredicate<Player, ItemStack> predicate) {
|
||||
this.putPredicate = predicate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemButton putItem(Function<ItemStack, ItemStack> putItemFunction) {
|
||||
this.putItemFunction = putItemFunction;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isItem() {
|
||||
return isItem(item);
|
||||
}
|
||||
|
||||
public boolean isItem(ItemStack item) {
|
||||
NBTItem nbtItem = new NBTItem(item);
|
||||
return nbtItem.has("gui_meta", NBTString.TYPE_ID) && ((NBTString) nbtItem.get("gui_meta")).getString().equals("item_button");
|
||||
}
|
||||
|
||||
public ItemButton clickItem(BiConsumer<Player, ItemStack> consumer) {
|
||||
this.clickItemConsumer = consumer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BiConsumer<Player, ItemStack> getClickItemConsumer() {
|
||||
return clickItemConsumer;
|
||||
}
|
||||
|
||||
public Function<ItemStack, ItemStack> getPutItemFunction() {
|
||||
return putItemFunction;
|
||||
}
|
||||
|
||||
public BiPredicate<Player, ItemStack> getPutPredicate() {
|
||||
return putPredicate;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.io.yutian.elementoriginlib.gui.button;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class ItemSlotButton extends Button {
|
||||
|
||||
private Consumer<ItemStack> putItemFunction;
|
||||
private Consumer<ItemStack> pickItemFunction;
|
||||
|
||||
private boolean canPut = true;
|
||||
|
||||
public ItemSlotButton() {
|
||||
super(new ItemStack(Material.AIR));
|
||||
}
|
||||
|
||||
public ItemSlotButton putItem(Consumer<ItemStack> putItemConsumer) {
|
||||
this.putItemFunction = putItemConsumer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemSlotButton pickItem(Consumer<ItemStack> pickItemConsumer) {
|
||||
this.pickItemFunction = pickItemConsumer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemSlotButton canPut(boolean can) {
|
||||
this.canPut = can;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isCanPut() {
|
||||
return canPut;
|
||||
}
|
||||
|
||||
public Consumer<ItemStack> getPickItemFunction() {
|
||||
return pickItemFunction;
|
||||
}
|
||||
|
||||
public Consumer<ItemStack> getPutItemFunction() {
|
||||
return putItemFunction;
|
||||
}
|
||||
|
||||
}
|
81
src/main/java/com/io/yutian/elementoriginlib/lang/Lang.java
Normal file
81
src/main/java/com/io/yutian/elementoriginlib/lang/Lang.java
Normal file
|
@ -0,0 +1,81 @@
|
|||
package com.io.yutian.elementoriginlib.lang;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class Lang {
|
||||
|
||||
private static Map<Plugin, List<File>> langFileMap = new HashMap<>();
|
||||
|
||||
private static Map<String, String> langMap = new HashMap<>();
|
||||
|
||||
public static String get(String key) {
|
||||
return langMap.getOrDefault(key, "§o"+key);
|
||||
}
|
||||
|
||||
public static String get(String key, Object... args) {
|
||||
String s = langMap.getOrDefault(key, "§o"+key);
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
s = s.replace("$"+i, String.valueOf(args[i]));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
public static void reload(Plugin plugin) {
|
||||
if (!langFileMap.containsKey(plugin)) {
|
||||
return;
|
||||
}
|
||||
List<File> list = langFileMap.get(plugin);
|
||||
list.forEach(Lang::loadFile);
|
||||
}
|
||||
|
||||
public static void reload() {
|
||||
langMap.clear();
|
||||
for (List<File> files : langFileMap.values()) {
|
||||
files.forEach(Lang::loadFile);
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadFile(File file) {
|
||||
FileConfiguration fileConfiguration = YamlConfiguration.loadConfiguration(file);
|
||||
for (String key : fileConfiguration.getKeys(true)) {
|
||||
if (!fileConfiguration.isString(key)) {
|
||||
continue;
|
||||
}
|
||||
String string = fileConfiguration.getString(key);
|
||||
string = ChatColor.translateAlternateColorCodes('&', string);
|
||||
langMap.put(key, string);
|
||||
}
|
||||
}
|
||||
|
||||
public static void registerLangFile(Plugin plugin) {
|
||||
registerLangFile(plugin, getFile(plugin));
|
||||
}
|
||||
|
||||
public static void registerLangFile(Plugin plugin, File file) {
|
||||
if (!file.exists()) {
|
||||
return;
|
||||
}
|
||||
List<File> files = langFileMap.getOrDefault(plugin, new ArrayList<>());
|
||||
files.add(file);
|
||||
langFileMap.put(plugin, files);
|
||||
loadFile(file);
|
||||
}
|
||||
|
||||
public static File getFile(Plugin plugin) {
|
||||
File file = new File(plugin.getDataFolder()+File.separator+ "lang.yml");
|
||||
if (!file.exists()) {
|
||||
plugin.saveResource("lang.yml", false);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package com.io.yutian.elementoriginlib.list;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class PageList<T> {
|
||||
|
||||
private List<T> list;
|
||||
private Map<Integer, List<T>> map = new HashMap<>();
|
||||
private int amount;
|
||||
|
||||
public PageList(List<T> list, int amount) {
|
||||
this.list = list;
|
||||
this.amount = amount;
|
||||
if (list == null) {
|
||||
return;
|
||||
}
|
||||
if (list.size() <= amount) {
|
||||
List<T> newList = new ArrayList<T>();
|
||||
list.forEach(o-> newList.add(o));
|
||||
map.put(1, newList);
|
||||
} else {
|
||||
int x = 0;
|
||||
int c = list.size() / amount;
|
||||
for (int j = 0; j <= c;j++) {
|
||||
int min = j * amount;
|
||||
int max = (j+1) * amount;
|
||||
List<T> newList = new ArrayList<T>();
|
||||
for (int k = min; k < max; k++) {
|
||||
if (k >= list.size()) {
|
||||
break;
|
||||
}
|
||||
newList.add(list.get(k));
|
||||
}
|
||||
map.put(j+1, newList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
public List<T> getList(int page) {
|
||||
if (page <= 0) {
|
||||
page = 1;
|
||||
}
|
||||
return map.get(page);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package com.io.yutian.elementoriginlib.listener;
|
||||
|
||||
import com.io.yutian.elementoriginlib.gui.IGui;
|
||||
import com.io.yutian.elementoriginlib.gui.IGuiDrag;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.inventory.*;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public final class GuiHandlerListener extends IListener {
|
||||
|
||||
public GuiHandlerListener(Plugin plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onInventoryClick(InventoryClickEvent event) {
|
||||
if (event.getInventory().getHolder() == null) {
|
||||
return;
|
||||
}
|
||||
Player player = (Player) event.getWhoClicked();
|
||||
InventoryHolder holder = event.getInventory().getHolder();
|
||||
if (holder instanceof IGui iGui) {
|
||||
if (event.getClickedInventory() != event.getInventory()) {
|
||||
if (event.getAction().equals(InventoryAction.MOVE_TO_OTHER_INVENTORY) || event.getAction().equals(InventoryAction.COLLECT_TO_CURSOR)) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (event.getAction().equals(InventoryAction.HOTBAR_SWAP) || event.getAction().equals(InventoryAction.HOTBAR_MOVE_AND_READD)) {
|
||||
event.setCancelled(true);
|
||||
player.getInventory().setItemInOffHand(player.getInventory().getItemInOffHand());
|
||||
return;
|
||||
}
|
||||
int slot = event.getRawSlot();
|
||||
iGui.handler(player, slot, event);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryDrag(InventoryDragEvent event) {
|
||||
if (event.getInventory().getHolder() != null) {
|
||||
InventoryHolder inventoryHolder = event.getInventory().getHolder();
|
||||
if (inventoryHolder instanceof IGui) {
|
||||
if (inventoryHolder instanceof IGuiDrag iGuiDrag) {
|
||||
iGuiDrag.onInventoryDrag(event);
|
||||
} else {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryClose(InventoryCloseEvent event) {
|
||||
if (event.getInventory().getHolder() != null) {
|
||||
InventoryHolder inventoryHolder = event.getInventory().getHolder();
|
||||
if (inventoryHolder instanceof IGui iGui) {
|
||||
iGui.close(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.io.yutian.elementoriginlib.listener;
|
||||
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class IListener implements Listener {
|
||||
|
||||
public IListener(Plugin plugin) {
|
||||
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
||||
}
|
||||
|
||||
}
|
180
src/main/java/com/io/yutian/elementoriginlib/nbt/INBT.java
Normal file
180
src/main/java/com/io/yutian/elementoriginlib/nbt/INBT.java
Normal file
|
@ -0,0 +1,180 @@
|
|||
package com.io.yutian.elementoriginlib.nbt;
|
||||
|
||||
import net.minecraft.nbt.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface INBT {
|
||||
|
||||
Object getValue();
|
||||
|
||||
byte getTypeId();
|
||||
|
||||
private static String getNBTTag(byte typeByte) {
|
||||
return switch (typeByte) {
|
||||
case 1 -> "NBTTagByte";
|
||||
case 2 -> "NBTTagShort";
|
||||
case 3 -> "NBTTagInt";
|
||||
case 4 -> "NBTTagLong";
|
||||
case 5 -> "NBTTagFloat";
|
||||
case 6 -> "NBTTagDouble";
|
||||
case 7 -> "NBTTagByteArray";
|
||||
case 8 -> "NBTTagString";
|
||||
case 9 -> "NBTTagList";
|
||||
case 10 -> "NBTTagCompound";
|
||||
case 11 -> "NBTTagIntArray";
|
||||
case 12 -> "NBTTagLongArray";
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
static INBT asObject(Object object) {
|
||||
if (object instanceof Byte b) {
|
||||
return new NBTByte(b);
|
||||
} else if (object instanceof Short value) {
|
||||
return new NBTShort(value);
|
||||
} else if (object instanceof Integer value) {
|
||||
return new NBTInt(value);
|
||||
} else if (object instanceof Long value) {
|
||||
return new NBTLong(value);
|
||||
} else if (object instanceof Float value) {
|
||||
return new NBTFloat(value);
|
||||
} else if (object instanceof Double value) {
|
||||
return new NBTDouble(value);
|
||||
} else if (object instanceof byte[] value) {
|
||||
return new NBTByteArray(value);
|
||||
} else if (object instanceof String value) {
|
||||
return new NBTString(value);
|
||||
} else if (object instanceof int[] value) {
|
||||
return new NBTIntArray(value);
|
||||
} else if (object instanceof long[] value) {
|
||||
return new NBTLongArray(value);
|
||||
} else if (object instanceof Boolean b) {
|
||||
return new NBTByte((byte) (b ? 1 : 0));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static net.minecraft.nbt.NBTBase asNMS(INBT nbt) {
|
||||
byte type = nbt.getTypeId();
|
||||
switch (type) {
|
||||
case 1 -> {
|
||||
NBTByte nbtByte = (NBTByte) nbt;
|
||||
return NBTTagByte.a(nbtByte.getByte());
|
||||
}
|
||||
case 2 -> {
|
||||
NBTShort nbtShort = (NBTShort) nbt;
|
||||
return NBTTagShort.a(nbtShort.getShort());
|
||||
}
|
||||
case 3 -> {
|
||||
NBTInt nbtInt = (NBTInt) nbt;
|
||||
return NBTTagInt.a(nbtInt.getInt());
|
||||
}
|
||||
case 4 -> {
|
||||
NBTLong nbtLong = (NBTLong) nbt;
|
||||
return NBTTagLong.a(nbtLong.getLong());
|
||||
}
|
||||
case 5 -> {
|
||||
NBTFloat nbtfloat = (NBTFloat) nbt;
|
||||
return NBTTagFloat.a(nbtfloat.getFloat());
|
||||
}
|
||||
case 6 -> {
|
||||
NBTDouble nbtDouble = (NBTDouble) nbt;
|
||||
return NBTTagDouble.a(nbtDouble.getDouble());
|
||||
}
|
||||
case 7 -> {
|
||||
NBTByteArray nbtByteArray = (NBTByteArray) nbt;
|
||||
return new NBTTagByteArray(nbtByteArray.getByteArray());
|
||||
}
|
||||
case 8 -> {
|
||||
NBTString nbtString = (NBTString) nbt;
|
||||
return NBTTagString.a(nbtString.getString());
|
||||
}
|
||||
case 9 -> {
|
||||
NBTList nbtTagList = (NBTList) nbt;
|
||||
List<net.minecraft.nbt.NBTBase> list = new ArrayList<>();
|
||||
for (Object base : nbtTagList.getList()) {
|
||||
list.add(asNMS((INBT) base));
|
||||
}
|
||||
NBTTagList nbtTagList1 = new NBTTagList();
|
||||
for (net.minecraft.nbt.NBTBase nbt1 : list) {
|
||||
nbtTagList1.add(nbt1);
|
||||
}
|
||||
return nbtTagList1;
|
||||
}
|
||||
case 10 -> {
|
||||
NBTCompound nbtCompound = (NBTCompound) nbt;
|
||||
NBTTagCompound nbtTagCompound = new NBTTagCompound();
|
||||
for (String key : nbtCompound.keySet()) {
|
||||
INBT nbt1 = nbtCompound.get(key);
|
||||
nbtTagCompound.a(key, asNMS(nbt1));
|
||||
}
|
||||
return nbtTagCompound;
|
||||
}
|
||||
case 11 -> {
|
||||
NBTIntArray nbtIntArray = (NBTIntArray) nbt;
|
||||
return new NBTTagIntArray(nbtIntArray.getIntArray());
|
||||
}
|
||||
case 12 -> {
|
||||
NBTLongArray nbtLongArray = (NBTLongArray) nbt;
|
||||
return new NBTTagLongArray(nbtLongArray.getLongArray());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static INBT as(net.minecraft.nbt.NBTBase nbtBase) {
|
||||
byte type = nbtBase.a();
|
||||
switch (type) {
|
||||
case 1:
|
||||
NBTTagByte nbtTagByte = (NBTTagByte) nbtBase;
|
||||
return new NBTByte(nbtTagByte.h());
|
||||
case 2:
|
||||
NBTTagShort nbtTagShort = (NBTTagShort) nbtBase;
|
||||
return new NBTShort(nbtTagShort.g());
|
||||
case 3:
|
||||
NBTTagInt nbtTagInt = (NBTTagInt) nbtBase;
|
||||
return new NBTInt(nbtTagInt.f());
|
||||
case 4:
|
||||
NBTTagLong nbtTagLong = (NBTTagLong) nbtBase;
|
||||
return new NBTLong(nbtTagLong.e());
|
||||
case 5:
|
||||
NBTTagFloat nbtTagFloat = (NBTTagFloat) nbtBase;
|
||||
return new NBTFloat(nbtTagFloat.j());
|
||||
case 6:
|
||||
NBTTagDouble nbtTagDouble = (NBTTagDouble) nbtBase;
|
||||
return new NBTDouble(nbtTagDouble.i());
|
||||
case 7:
|
||||
NBTTagByteArray tagByteArray = (NBTTagByteArray) nbtBase;
|
||||
return new NBTByteArray(tagByteArray.d());
|
||||
case 8:
|
||||
NBTTagString nbtTagString = (NBTTagString) nbtBase;
|
||||
return new NBTString(nbtTagString.e_());
|
||||
case 9:
|
||||
NBTTagList nbtTagList = (NBTTagList) nbtBase;
|
||||
List<INBT> list = new ArrayList<>();
|
||||
for (net.minecraft.nbt.NBTBase base : nbtTagList) {
|
||||
list.add(as(base));
|
||||
}
|
||||
return new NBTList(list);
|
||||
case 10:
|
||||
NBTTagCompound nbtTagCompound = (NBTTagCompound) nbtBase;
|
||||
Map<String, INBT> map = new HashMap<>();
|
||||
for (String key : nbtTagCompound.d()) {
|
||||
map.put(key, as(nbtTagCompound.c(key)));
|
||||
}
|
||||
return new NBTCompound(map);
|
||||
case 11:
|
||||
NBTTagIntArray nbtTagIntArray = (NBTTagIntArray) nbtBase;
|
||||
return new NBTIntArray(nbtTagIntArray.f());
|
||||
case 12:
|
||||
NBTTagLongArray nbtTagLongArray = (NBTTagLongArray) nbtBase;
|
||||
return new NBTLongArray(nbtTagLongArray.f());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package com.io.yutian.elementoriginlib.nbt;
|
||||
|
||||
public class NBTByte extends NBTNumber {
|
||||
|
||||
public static byte TYPE_ID = 1;
|
||||
|
||||
private byte value;
|
||||
|
||||
public NBTByte(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public NBTByte() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getTypeId() {
|
||||
return TYPE_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getShort() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getByte() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public static NBTByte a(boolean var0) {
|
||||
return var0 ? new NBTByte((byte) 1) : new NBTByte((byte) 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
NBTByte nbtByte = (NBTByte) o;
|
||||
return value == nbtByte.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NBTByte{" +
|
||||
"value=" + value +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package com.io.yutian.elementoriginlib.nbt;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class NBTByteArray implements INBT {
|
||||
|
||||
public static byte TYPE_ID = 7;
|
||||
|
||||
private byte[] value;
|
||||
|
||||
public NBTByteArray(byte[] value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public byte[] getByteArray() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getTypeId() {
|
||||
return TYPE_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
NBTByteArray that = (NBTByteArray) o;
|
||||
return Arrays.equals(value, that.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NBTByteArray{" +
|
||||
"value=" + Arrays.toString(value) +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,267 @@
|
|||
package com.io.yutian.elementoriginlib.nbt;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class NBTCompound implements INBT {
|
||||
|
||||
public static byte TYPE_ID = 10;
|
||||
|
||||
private Map<String, INBT> nbtMap = new HashMap<>();
|
||||
|
||||
public NBTCompound() {
|
||||
}
|
||||
|
||||
public NBTCompound(Map<String, INBT> nbtMap) {
|
||||
this.nbtMap = nbtMap;
|
||||
}
|
||||
|
||||
public Set<String> keySet() {
|
||||
return nbtMap.keySet();
|
||||
}
|
||||
|
||||
public Map<String, INBT> getMap() {
|
||||
return nbtMap;
|
||||
}
|
||||
|
||||
public void remove(String key) {
|
||||
nbtMap.remove(key);
|
||||
}
|
||||
|
||||
public boolean hasKey(String key) {
|
||||
return this.nbtMap.containsKey(key);
|
||||
}
|
||||
|
||||
public boolean hasKey(String key, byte id) {
|
||||
return this.nbtMap.containsKey(key) && this.nbtMap.get(key).getTypeId() == id;
|
||||
}
|
||||
|
||||
public boolean hasKey(String key, int id) {
|
||||
return this.nbtMap.containsKey(key) && this.nbtMap.get(key).getTypeId() == id;
|
||||
}
|
||||
|
||||
public NBTList getList(String key) {
|
||||
INBT list = this.nbtMap.get(key);
|
||||
if (list == null || list.getTypeId() != 9) {
|
||||
return null;
|
||||
}
|
||||
return (NBTList) list;
|
||||
}
|
||||
|
||||
public NBTCompound getCompound(String key) {
|
||||
INBT comound = this.nbtMap.get(key);
|
||||
if (comound == null || comound.getTypeId() != 10) {
|
||||
return null;
|
||||
}
|
||||
return (NBTCompound) comound;
|
||||
}
|
||||
|
||||
public INBT get(String key) {
|
||||
return this.nbtMap.get(key);
|
||||
}
|
||||
|
||||
public int getInt(String key) {
|
||||
INBT nbt = this.nbtMap.get(key);
|
||||
if (nbt == null || nbt.getTypeId() != 3) {
|
||||
return 0;
|
||||
}
|
||||
return ((NBTInt) nbt).getInt();
|
||||
}
|
||||
|
||||
public String getString(String key) {
|
||||
INBT nbt = this.nbtMap.get(key);
|
||||
if (nbt == null || nbt.getTypeId() != 8) {
|
||||
return null;
|
||||
}
|
||||
return ((NBTString) nbt).getString();
|
||||
}
|
||||
|
||||
public double getDouble(String key) {
|
||||
INBT nbt = this.nbtMap.get(key);
|
||||
if (nbt == null || nbt.getTypeId() != 6) {
|
||||
return 0.0;
|
||||
}
|
||||
return ((NBTDouble) nbt).getDouble();
|
||||
}
|
||||
|
||||
public float getFloat(String key) {
|
||||
INBT nbt = this.nbtMap.get(key);
|
||||
if (nbt == null || nbt.getTypeId() != 5) {
|
||||
return 0.0F;
|
||||
}
|
||||
return ((NBTFloat) nbt).getFloat();
|
||||
}
|
||||
|
||||
public short getShort(String key) {
|
||||
INBT nbt = this.nbtMap.get(key);
|
||||
if (nbt == null || nbt.getTypeId() != 2) {
|
||||
return 0;
|
||||
}
|
||||
return ((NBTShort) nbt).getShort();
|
||||
}
|
||||
|
||||
public long getLong(String key) {
|
||||
INBT nbt = this.nbtMap.get(key);
|
||||
if (nbt == null || nbt.getTypeId() != 4) {
|
||||
return 0;
|
||||
}
|
||||
return ((NBTLong) nbt).getLong();
|
||||
}
|
||||
|
||||
public byte getByte(String key) {
|
||||
INBT nbt = this.nbtMap.get(key);
|
||||
if (nbt == null || nbt.getTypeId() != 1) {
|
||||
return 0;
|
||||
}
|
||||
return ((NBTByte) nbt).getByte();
|
||||
}
|
||||
|
||||
public NBTByteArray getByteArray(String key) {
|
||||
INBT nbt = this.nbtMap.get(key);
|
||||
if (nbt == null || nbt.getTypeId() != 7) {
|
||||
return null;
|
||||
}
|
||||
return (NBTByteArray) nbt;
|
||||
}
|
||||
|
||||
public NBTIntArray getIntArray(String key) {
|
||||
INBT nbt = this.nbtMap.get(key);
|
||||
if (nbt == null || nbt.getTypeId() != 11) {
|
||||
return null;
|
||||
}
|
||||
return (NBTIntArray) nbt;
|
||||
}
|
||||
|
||||
public NBTLongArray getLongArray(String key) {
|
||||
INBT nbt = this.nbtMap.get(key);
|
||||
if (nbt == null || nbt.getTypeId() != 12) {
|
||||
return null;
|
||||
}
|
||||
return (NBTLongArray) nbt;
|
||||
}
|
||||
|
||||
public boolean getBoolean(String key) {
|
||||
INBT nbt = this.nbtMap.get(key);
|
||||
if (nbt == null || nbt.getTypeId() != 1) {
|
||||
return false;
|
||||
}
|
||||
return ((NBTByte) nbt).getByte() != 0;
|
||||
}
|
||||
|
||||
public UUID getUUID(String key) {
|
||||
INBT nbt = this.nbtMap.get(key);
|
||||
if (nbt == null || nbt.getTypeId() != 11) {
|
||||
return null;
|
||||
}
|
||||
return a(((NBTIntArray) nbt).getIntArray());
|
||||
}
|
||||
|
||||
public void put(String key, INBT nbt) {
|
||||
this.nbtMap.put(key, nbt);
|
||||
}
|
||||
|
||||
public void putString(String key, String value) {
|
||||
put(key, new NBTString(value));
|
||||
}
|
||||
|
||||
public void putInt(String key, int value) {
|
||||
put(key, new NBTInt(value));
|
||||
}
|
||||
|
||||
public void putShort(String key, short value) {
|
||||
put(key, new NBTShort(value));
|
||||
}
|
||||
|
||||
public void putDouble(String key, double value) {
|
||||
put(key, new NBTDouble(value));
|
||||
}
|
||||
|
||||
public void putLong(String key, long value) {
|
||||
put(key, new NBTLong(value));
|
||||
}
|
||||
|
||||
public void putFloat(String key, float value) {
|
||||
put(key, new NBTFloat(value));
|
||||
}
|
||||
|
||||
public void putByte(String key, byte value) {
|
||||
put(key, new NBTByte(value));
|
||||
}
|
||||
|
||||
public void putBoolean(String key, boolean value) {
|
||||
put(key, NBTByte.a(value));
|
||||
}
|
||||
|
||||
public void putUUID(String key, UUID uuid) {
|
||||
put(key, new NBTIntArray(a(uuid)));
|
||||
}
|
||||
|
||||
private static UUID a(int[] var0) {
|
||||
return new UUID((long)var0[0] << 32 | (long)var0[1] & 4294967295L, (long)var0[2] << 32 | (long)var0[3] & 4294967295L);
|
||||
}
|
||||
|
||||
private static int[] a(UUID var0) {
|
||||
long var1 = var0.getMostSignificantBits();
|
||||
long var3 = var0.getLeastSignificantBits();
|
||||
return a(var1, var3);
|
||||
}
|
||||
|
||||
private static int[] a(long var0, long var2) {
|
||||
return new int[]{(int)(var0 >> 32), (int)var0, (int)(var2 >> 32), (int)var2};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return nbtMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getTypeId() {
|
||||
return TYPE_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
NBTCompound that = (NBTCompound) o;
|
||||
Map<String, INBT> nbtMap1 = this.nbtMap;
|
||||
Map<String, INBT> nbtMap2 = that.nbtMap;
|
||||
if (nbtMap1.size() != nbtMap2.size()) {
|
||||
return false;
|
||||
}
|
||||
for (Map.Entry<String, INBT> entry : nbtMap1.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
INBT value = entry.getValue();
|
||||
if (!nbtMap2.containsKey(key)) {
|
||||
return false;
|
||||
}
|
||||
INBT nbt2 = nbtMap2.get(key);
|
||||
Object object1 = value.getValue();
|
||||
Object object2 = nbt2.getValue();
|
||||
if (value == null && nbt2 != null) {
|
||||
return false;
|
||||
} else if (object1 instanceof Number && object2 instanceof Number) {
|
||||
if (Double.compare(((Number) object1).doubleValue(), ((Number) object2).doubleValue()) != 0) {
|
||||
return false;
|
||||
}
|
||||
} else if (!object1.equals(object2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(nbtMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NBTCompound{" +
|
||||
"nbtMap=" + nbtMap +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package com.io.yutian.elementoriginlib.nbt;
|
||||
|
||||
public class NBTDouble extends NBTNumber {
|
||||
|
||||
public static byte TYPE_ID = 6;
|
||||
|
||||
private double value;
|
||||
|
||||
public NBTDouble(double value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public NBTDouble() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getTypeId() {
|
||||
return TYPE_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong() {
|
||||
return (long) this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt() {
|
||||
return floor(this.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getShort() {
|
||||
return (short)(floor(this.value) & 0xFFFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getByte() {
|
||||
return (byte)(floor(this.value) & 0xFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat() {
|
||||
return (float) this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
NBTDouble nbtDouble = (NBTDouble) o;
|
||||
return Double.compare(value, nbtDouble.value) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Double.hashCode(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NBTDouble{" +
|
||||
"value=" + value +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package com.io.yutian.elementoriginlib.nbt;
|
||||
|
||||
public class NBTFloat extends NBTNumber {
|
||||
|
||||
public static byte TYPE_ID = 5;
|
||||
|
||||
private float value;
|
||||
|
||||
public NBTFloat(float value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getTypeId() {
|
||||
return TYPE_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong() {
|
||||
return (long) this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt() {
|
||||
return floor(this.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getShort() {
|
||||
return (short)(floor(this.value) & 0xFFFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getByte() {
|
||||
return (byte)(floor(this.value) & 0xFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
NBTFloat nbtFloat = (NBTFloat) o;
|
||||
return Float.compare(value, nbtFloat.value) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Float.hashCode(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NBTFloat{" +
|
||||
"value=" + value +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.io.yutian.elementoriginlib.nbt;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class NBTHelper {
|
||||
|
||||
@Nullable
|
||||
public static INBT convert(Object object) {
|
||||
if (object instanceof Byte) {
|
||||
return new NBTByte((byte) object);
|
||||
} else if (object instanceof Short) {
|
||||
return new NBTShort((short) object);
|
||||
} else if (object instanceof Integer) {
|
||||
return new NBTInt((int) object);
|
||||
} else if (object instanceof Long) {
|
||||
return new NBTLong((long) object);
|
||||
} else if (object instanceof Float) {
|
||||
return new NBTFloat((float) object);
|
||||
} else if (object instanceof Double) {
|
||||
return new NBTDouble((double) object);
|
||||
} else if (object instanceof byte[]) {
|
||||
return new NBTByteArray((byte[]) object);
|
||||
} else if (object instanceof String) {
|
||||
return new NBTString((String) object);
|
||||
} else if (object instanceof int[]) {
|
||||
return new NBTIntArray((int[]) object);
|
||||
} else if (object instanceof long[]) {
|
||||
return new NBTLongArray((long[]) object);
|
||||
} else if (object instanceof Boolean) {
|
||||
return new NBTByte((byte) ((boolean)object ? 1 : 0));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Object convertNMSNBT(INBT nbt) {
|
||||
return INBT.asNMS(nbt);
|
||||
}
|
||||
|
||||
}
|
73
src/main/java/com/io/yutian/elementoriginlib/nbt/NBTInt.java
Normal file
73
src/main/java/com/io/yutian/elementoriginlib/nbt/NBTInt.java
Normal file
|
@ -0,0 +1,73 @@
|
|||
package com.io.yutian.elementoriginlib.nbt;
|
||||
|
||||
public class NBTInt extends NBTNumber {
|
||||
|
||||
public static byte TYPE_ID = 3;
|
||||
|
||||
private int value;
|
||||
|
||||
public NBTInt(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getTypeId() {
|
||||
return TYPE_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getShort() {
|
||||
return (short)(this.value & 0xFFFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getByte() {
|
||||
return (byte)(this.value & 0xFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
NBTInt nbtInt = (NBTInt) o;
|
||||
return value == nbtInt.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NBTInt{" +
|
||||
"value=" + value +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package com.io.yutian.elementoriginlib.nbt;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class NBTIntArray implements INBT {
|
||||
|
||||
public static byte TYPE_ID = 11;
|
||||
|
||||
private int[] value;
|
||||
|
||||
public NBTIntArray(int[] value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int[] getIntArray() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getTypeId() {
|
||||
return TYPE_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
NBTIntArray that = (NBTIntArray) o;
|
||||
return Arrays.equals(value, that.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package com.io.yutian.elementoriginlib.nbt;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class NBTItem {
|
||||
|
||||
private ItemStack originalItemStack;
|
||||
private net.minecraft.world.item.ItemStack nmsItemStack;
|
||||
|
||||
protected ItemStack resultItemStack;
|
||||
|
||||
public NBTItem(ItemStack itemStack) {
|
||||
this.originalItemStack = itemStack;
|
||||
this.nmsItemStack = CraftItemStack.asNMSCopy(itemStack);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public NBTCompound getTag() {
|
||||
NBTTagCompound tag = nmsItemStack.u();
|
||||
if (tag == null) {
|
||||
tag = new NBTTagCompound();
|
||||
}
|
||||
return (NBTCompound) INBT.as(tag);
|
||||
}
|
||||
|
||||
public boolean has(String key) {
|
||||
NBTCompound nbtCompound = getTag();
|
||||
return nbtCompound.hasKey(key);
|
||||
}
|
||||
|
||||
public boolean has(String key, int type) {
|
||||
NBTCompound nbtCompound = getTag();
|
||||
return nbtCompound.hasKey(key, type);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public INBT get(String key) {
|
||||
NBTCompound nbtCompound = getTag();
|
||||
return nbtCompound.hasKey(key) ? nbtCompound.get(key) : null;
|
||||
}
|
||||
|
||||
public void editTag(Consumer<NBTCompound> consumer) {
|
||||
NBTCompound tag = getTag();
|
||||
consumer.accept(tag);
|
||||
setTag(tag);
|
||||
}
|
||||
|
||||
public void setTag(NBTCompound nbtCompound) {
|
||||
nmsItemStack.c((NBTTagCompound) INBT.asNMS(nbtCompound));
|
||||
resultItemStack = CraftItemStack.asBukkitCopy(nmsItemStack);
|
||||
}
|
||||
|
||||
public ItemStack getOriginalItemStack() {
|
||||
return originalItemStack;
|
||||
}
|
||||
|
||||
public ItemStack getItemStack() {
|
||||
return resultItemStack;
|
||||
}
|
||||
|
||||
public net.minecraft.world.item.ItemStack getNMSItemStack() {
|
||||
return nmsItemStack;
|
||||
}
|
||||
|
||||
public static NBTItem build(ItemStack itemStack) {
|
||||
return new NBTItem(itemStack);
|
||||
}
|
||||
|
||||
public static NBTItem build(NBTCompound nbtCompound) {
|
||||
net.minecraft.world.item.ItemStack nmsItemStack = net.minecraft.world.item.ItemStack.a((NBTTagCompound) INBT.asNMS(nbtCompound));
|
||||
return new NBTItem(CraftItemStack.asBukkitCopy(nmsItemStack));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package com.io.yutian.elementoriginlib.nbt;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class NBTList<T extends INBT> implements INBT {
|
||||
|
||||
public static byte TYPE_ID = 9;
|
||||
|
||||
private List<T> value = new ArrayList<>();
|
||||
private byte type = 0;
|
||||
|
||||
public NBTList(List<T> value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public NBTList() {
|
||||
}
|
||||
|
||||
public List<T> getList() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return value.size();
|
||||
}
|
||||
|
||||
public T get(int index) {
|
||||
if (index > value.size()) {
|
||||
return null;
|
||||
}
|
||||
return value.get(index);
|
||||
}
|
||||
|
||||
public void add(T nbtBase) {
|
||||
if (nbtBase.getTypeId() == 0) {
|
||||
return;
|
||||
}
|
||||
if (this.type == 0) {
|
||||
this.type = nbtBase.getTypeId();
|
||||
} else if (this.type != nbtBase.getTypeId()) {
|
||||
return;
|
||||
}
|
||||
this.value.add(nbtBase);
|
||||
}
|
||||
|
||||
public void remove(int index) {
|
||||
this.value.remove(index);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return value.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getTypeId() {
|
||||
return TYPE_ID;
|
||||
}
|
||||
|
||||
public byte getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
NBTList<?> nbtList = (NBTList<?>) o;
|
||||
return type == nbtList.type && Objects.equals(value, nbtList.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = Objects.hashCode(value);
|
||||
result = 31 * result + type;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NBTList{" +
|
||||
"value=" + value +
|
||||
", type=" + type +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package com.io.yutian.elementoriginlib.nbt;
|
||||
|
||||
public class NBTLong extends NBTNumber {
|
||||
|
||||
public static byte TYPE_ID = 4;
|
||||
|
||||
private long value;
|
||||
|
||||
public NBTLong(long value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public NBTLong() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getTypeId() {
|
||||
return TYPE_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt() {
|
||||
return (int)(this.value & 0x7fffffffffffffffL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getShort() {
|
||||
return (short)(this.value & 0xFFFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getByte() {
|
||||
return (byte)(this.value & 0xFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat() {
|
||||
return (float) this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NBTLong{" +
|
||||
"value=" + value +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
NBTLong nbtLong = (NBTLong) o;
|
||||
return value == nbtLong.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Long.hashCode(value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package com.io.yutian.elementoriginlib.nbt;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class NBTLongArray implements INBT {
|
||||
|
||||
public static byte TYPE_ID = 12;
|
||||
|
||||
private long[] value;
|
||||
|
||||
public NBTLongArray(long[] value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public long[] getLongArray() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getTypeId() {
|
||||
return TYPE_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
NBTLongArray that = (NBTLongArray) o;
|
||||
return Arrays.equals(value, that.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package com.io.yutian.elementoriginlib.nbt;
|
||||
|
||||
public abstract class NBTNumber implements INBT {
|
||||
|
||||
public abstract long getLong();
|
||||
|
||||
public abstract int getInt();
|
||||
|
||||
public abstract short getShort();
|
||||
|
||||
public abstract byte getByte();
|
||||
|
||||
public abstract double getDouble();
|
||||
|
||||
public abstract float getFloat();
|
||||
|
||||
public static int floor(double paramDouble) {
|
||||
int i = (int)paramDouble;
|
||||
return paramDouble < i ? i - 1 : i;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package com.io.yutian.elementoriginlib.nbt;
|
||||
|
||||
public class NBTShort extends NBTNumber {
|
||||
|
||||
public static byte TYPE_ID = 2;
|
||||
|
||||
private short value;
|
||||
|
||||
public NBTShort(short value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public NBTShort() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getTypeId() {
|
||||
return TYPE_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getShort() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getByte() {
|
||||
return (byte)(this.value & 0xFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
NBTShort nbtShort = (NBTShort) o;
|
||||
return value == nbtShort.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NBTShort{" +
|
||||
"value=" + value +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package com.io.yutian.elementoriginlib.nbt;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class NBTString implements INBT {
|
||||
|
||||
public static byte TYPE_ID = 8;
|
||||
|
||||
private String value;
|
||||
|
||||
public NBTString(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public NBTString() {
|
||||
}
|
||||
|
||||
public String getString() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getTypeId() {
|
||||
return TYPE_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
NBTString nbtString = (NBTString) o;
|
||||
return Objects.equals(value, nbtString.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NBTString{" +
|
||||
"value='" + value + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package com.io.yutian.elementoriginlib.point;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class DirectionPoint extends Point {
|
||||
|
||||
private float yaw;
|
||||
private float pitch;
|
||||
|
||||
public DirectionPoint(int x, int y, int z, float yaw, float pitch) {
|
||||
super(x, y, z);
|
||||
this.yaw = yaw;
|
||||
this.pitch = pitch;
|
||||
}
|
||||
|
||||
public DirectionPoint(double x, double y, double z) {
|
||||
this(x, y, z, 0f, 0f);
|
||||
}
|
||||
|
||||
public DirectionPoint(double x, double y, double z, float yaw, float pitch) {
|
||||
super(x, y, z);
|
||||
this.yaw = yaw;
|
||||
this.pitch = pitch;
|
||||
}
|
||||
|
||||
public float getPitch() {
|
||||
return pitch;
|
||||
}
|
||||
|
||||
public float getYaw() {
|
||||
return yaw;
|
||||
}
|
||||
|
||||
public void setYaw(float yaw) {
|
||||
this.yaw = yaw;
|
||||
}
|
||||
|
||||
public void setPitch(float pitch) {
|
||||
this.pitch = pitch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location toLocation(World world) {
|
||||
return new Location(world, getX(), getY(), getZ(), yaw, pitch);
|
||||
}
|
||||
|
||||
public static DirectionPoint of(Location location) {
|
||||
return new DirectionPoint(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DirectionPoint{" +
|
||||
"x=" + getX() +
|
||||
", y=" + getY() +
|
||||
", z=" + getZ() +
|
||||
", yaw=" + yaw +
|
||||
", pitch=" + pitch +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
DirectionPoint that = (DirectionPoint) o;
|
||||
return super.equals(o) && Float.compare(that.yaw, yaw) == 0 && Float.compare(that.pitch, pitch) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), yaw, pitch);
|
||||
}
|
||||
|
||||
public static DirectionPoint deserialize(ConfigurationSection section) {
|
||||
return new DirectionPoint(section.getDouble("x"), section.getDouble("y"), section.getDouble("z"), (float) section.getDouble("yaw"), (float) section.getDouble("pitch"));
|
||||
}
|
||||
|
||||
}
|
101
src/main/java/com/io/yutian/elementoriginlib/point/Point.java
Normal file
101
src/main/java/com/io/yutian/elementoriginlib/point/Point.java
Normal file
|
@ -0,0 +1,101 @@
|
|||
package com.io.yutian.elementoriginlib.point;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class Point {
|
||||
|
||||
private double x;
|
||||
private double y;
|
||||
private double z;
|
||||
|
||||
public Point(int x, int y, int z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public Point(double x, double y, double z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public int getBlockX() {
|
||||
return (int) Math.floor(x);
|
||||
}
|
||||
|
||||
public int getBlockY() {
|
||||
return (int) Math.floor(y);
|
||||
}
|
||||
|
||||
public int getBlockZ() {
|
||||
return (int) Math.floor(z);
|
||||
}
|
||||
|
||||
public double getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public double getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public double getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public void setX(double x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public void setY(double y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public void setZ(double z) {
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public Point clone() {
|
||||
return new Point(x, y, z);
|
||||
}
|
||||
|
||||
public Location toLocation(World world) {
|
||||
return new Location(world, x, y, z, 0, 0);
|
||||
}
|
||||
|
||||
public static Point of(Location location) {
|
||||
return new Point(location.getX(), location.getY(), location.getZ());
|
||||
}
|
||||
|
||||
public static Point deserialize(ConfigurationSection section) {
|
||||
return new Point(section.getDouble("x"), section.getDouble("y"), section.getDouble("z"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Point{" +
|
||||
"x=" + x +
|
||||
", y=" + y +
|
||||
", z=" + z +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Point point = (Point) o;
|
||||
return Double.compare(point.x, x) == 0 && Double.compare(point.y, y) == 0 && Double.compare(point.z, z) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(x, y, z);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package com.io.yutian.elementoriginlib.point;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
public class Region {
|
||||
|
||||
private World world;
|
||||
private Point min;
|
||||
private Point max;
|
||||
|
||||
public Region(World world, Point min, Point max) {
|
||||
this.world = world;
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public World getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
public Point getMin() {
|
||||
return min;
|
||||
}
|
||||
|
||||
public Point getMax() {
|
||||
return max;
|
||||
}
|
||||
|
||||
public static Region deserialize(ConfigurationSection section) {
|
||||
World world1 = Bukkit.getWorld(section.getString("world"));
|
||||
Point point1 = Point.deserialize(section.getConfigurationSection("min"));
|
||||
Point point2 = Point.deserialize(section.getConfigurationSection("max"));
|
||||
return new Region(world1, point1, point2);
|
||||
}
|
||||
|
||||
public boolean isInRegion(Location location) {
|
||||
if (!location.getWorld().getName().equalsIgnoreCase(world.getName())) {
|
||||
return false;
|
||||
}
|
||||
return (location.getBlockX() >= this.min.getX()
|
||||
&& location.getBlockX() <= this.max.getX()
|
||||
&& location.getBlockY() >= this.min.getY()
|
||||
&& location.getBlockY() <= this.max.getY()
|
||||
&& location.getBlockZ() >= this.min.getZ()
|
||||
&& location.getBlockZ() <= this.max.getZ());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.io.yutian.elementoriginlib.redis;
|
||||
|
||||
import redis.clients.jedis.Jedis;
|
||||
|
||||
public interface IJedisGetter {
|
||||
|
||||
Jedis getRedis();
|
||||
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
package com.io.yutian.elementoriginlib.redis;
|
||||
|
||||
import com.io.yutian.elementoriginlib.ElementOriginLib;
|
||||
import com.io.yutian.elementoriginlib.util.Pair;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import redis.clients.jedis.Jedis;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class RedisCacheSyncTimer {
|
||||
|
||||
private static final String LOCK_KEY = "sync_lock";
|
||||
private static final int LOCK_EXPIRE_SECONDS = 290;
|
||||
private final Map<Plugin, PluginInfo> pluginInfos = new HashMap<>();
|
||||
|
||||
private BukkitTask task;
|
||||
|
||||
public RedisCacheSyncTimer() {
|
||||
task = new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (pluginInfos.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (Map.Entry<Plugin, PluginInfo> entry : pluginInfos.entrySet()) {
|
||||
Plugin plugin = entry.getKey();
|
||||
if (!plugin.isEnabled()) {
|
||||
continue;
|
||||
}
|
||||
PluginInfo pluginInfo = entry.getValue();
|
||||
String lockKey = LOCK_KEY + "_" + plugin.getName();
|
||||
IJedisGetter jedisGetter = pluginInfo.getJedisGetter();
|
||||
try (Jedis jedis = jedisGetter.getRedis()) {
|
||||
long lockResult = jedis.setnx(lockKey, "locked");
|
||||
if (lockResult != 1) {
|
||||
continue;
|
||||
}
|
||||
jedis.expire(lockKey, LOCK_EXPIRE_SECONDS);
|
||||
for (Map.Entry<Pair<String, String>, RedisCacheSynchronizer> entry1 : entry.getValue().getSynchronizers().entrySet()) {
|
||||
Pair<String, String> key = entry1.getKey();
|
||||
RedisCacheSynchronizer synchronizer = entry1.getValue();
|
||||
String k1 = key.first();
|
||||
String k2 = key.second();
|
||||
for (String k : jedis.keys(k1+":*")) {
|
||||
String data = null;
|
||||
if (k2 == null) {
|
||||
data = jedis.get(k);
|
||||
} else {
|
||||
data = jedis.hget(k, k2);
|
||||
}
|
||||
if (data != null) {
|
||||
String finalData = data;
|
||||
synchronizer.sync(k, finalData);
|
||||
if (k2 == null) {
|
||||
jedis.del(k);
|
||||
} else {
|
||||
jedis.hdel(k, k2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.runTaskTimerAsynchronously(ElementOriginLib.inst(), 1200L, 5 * 60 * 20L);
|
||||
}
|
||||
|
||||
public void registerSynchronizer(Plugin plugin, IJedisGetter jedisGetter, Pair<String, String> key, RedisCacheSynchronizer synchronizer) {
|
||||
PluginInfo pluginInfo = pluginInfos.computeIfAbsent(plugin, k -> new PluginInfo(jedisGetter));
|
||||
pluginInfo.addSynchronizer(key, synchronizer);
|
||||
pluginInfos.put(plugin, pluginInfo);
|
||||
}
|
||||
|
||||
class PluginInfo {
|
||||
|
||||
private IJedisGetter jedisGetter;
|
||||
private Map<Pair<String, String>, RedisCacheSynchronizer> synchronizers;
|
||||
|
||||
public PluginInfo(IJedisGetter jedisGetter) {
|
||||
this.jedisGetter = jedisGetter;
|
||||
this.synchronizers = new HashMap<>();
|
||||
}
|
||||
|
||||
public void addSynchronizer(Pair<String, String> key, RedisCacheSynchronizer synchronizer) {
|
||||
if (key == null || synchronizer == null) {
|
||||
return;
|
||||
}
|
||||
if (synchronizers.containsKey(key)) {
|
||||
throw new IllegalArgumentException("Key already registered: " + key);
|
||||
}
|
||||
synchronizers.put(key, synchronizer);
|
||||
}
|
||||
|
||||
public IJedisGetter getJedisGetter() {
|
||||
return jedisGetter;
|
||||
}
|
||||
|
||||
public Map<Pair<String, String>, RedisCacheSynchronizer> getSynchronizers() {
|
||||
return synchronizers;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.io.yutian.elementoriginlib.redis;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface RedisCacheSynchronizer {
|
||||
|
||||
void sync(String key, String data);
|
||||
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package com.io.yutian.elementoriginlib.redis;
|
||||
|
||||
import com.io.yutian.elementoriginlib.util.FileUtil;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
import redis.clients.jedis.JedisPoolConfig;
|
||||
|
||||
import java.io.File;
|
||||
import java.time.Duration;
|
||||
import java.util.Set;
|
||||
|
||||
public class RedisIO implements IJedisGetter {
|
||||
|
||||
private JedisPool jedisPool;
|
||||
|
||||
public void init(Plugin plugin) {
|
||||
File file = FileUtil.getFile(plugin, "", "redis.yml");
|
||||
if (!file.exists()) {
|
||||
plugin.saveResource("redis.yml", false);
|
||||
}
|
||||
FileConfiguration configuration = YamlConfiguration.loadConfiguration(file);
|
||||
String redisServer = configuration.getString("server", "localhost");
|
||||
int redisPort = configuration.getInt("port", 6379);
|
||||
String redisPassword = configuration.getString("password");
|
||||
if (redisPassword != null && (redisPassword.isEmpty() || redisPassword.equals("none"))) {
|
||||
redisPassword = null;
|
||||
}
|
||||
try {
|
||||
String finalRedisPassword = redisPassword;
|
||||
JedisPoolConfig config = new JedisPoolConfig();
|
||||
config.setMaxTotal(1024);
|
||||
config.setMaxWait(Duration.ofMillis(10000));
|
||||
jedisPool = new JedisPool(config, redisServer, redisPort, 0, finalRedisPassword);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (jedisPool != null && !jedisPool.isClosed()) {
|
||||
jedisPool.close();
|
||||
jedisPool.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
public JedisPool getJedisPool() {
|
||||
return jedisPool;
|
||||
}
|
||||
|
||||
public Set<String> getKeys(String arg) {
|
||||
try (Jedis resource = jedisPool.getResource()) {
|
||||
return resource.keys(arg);
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(String key) {
|
||||
try (Jedis resource = jedisPool.getResource()) {
|
||||
resource.del(key);
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(String key, String field) {
|
||||
try (Jedis resource = jedisPool.getResource()) {
|
||||
resource.hdel(key, field);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean has(String key) {
|
||||
try (Jedis resource = jedisPool.getResource()) {
|
||||
return resource.exists(key);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean has(String key, String field) {
|
||||
try (Jedis resource = jedisPool.getResource()) {
|
||||
return resource.hexists(key, field);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Jedis getRedis() {
|
||||
return jedisPool.getResource();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.io.yutian.elementoriginlib.serialize;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
public interface ISerializable<T> {
|
||||
|
||||
JSONObject serialize();
|
||||
|
||||
T deserialize(JSONObject jsonObject);
|
||||
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
package com.io.yutian.elementoriginlib.serialize;
|
||||
|
||||
import com.io.yutian.elementoriginlib.exception.SerializeException;
|
||||
import com.io.yutian.elementoriginlib.serialize.serializers.ItemStackSerializer;
|
||||
import com.io.yutian.elementoriginlib.serialize.serializers.UUIDSerializer;
|
||||
import com.io.yutian.elementoriginlib.util.ReflectionUtil;
|
||||
import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.*;
|
||||
|
||||
public class SerializeHelper {
|
||||
|
||||
private static Map<Class<?>, Serializer> serializers = new HashMap<>();
|
||||
|
||||
public static <T, V> void registerSerializer(Class<T> clazz, Serializer<T> serializer) {
|
||||
serializers.put(clazz, serializer);
|
||||
}
|
||||
|
||||
public static <T> JSONObject serialize(T obj) throws SerializeException {
|
||||
try {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
Class clazz = obj.getClass();
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
field.setAccessible(true);
|
||||
if (field.isAnnotationPresent(SerializeIgnore.class)) {
|
||||
continue;
|
||||
}
|
||||
Object value = field.get(obj);
|
||||
if (value == null) {
|
||||
continue;
|
||||
}
|
||||
Object serializeValue = serializeValue(value);
|
||||
jsonObject.put(field.getName(), serializeValue);
|
||||
}
|
||||
return jsonObject;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new SerializeException(obj.getClass(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T deserialize(Class<T> clazz, JSONObject jsonObject) throws SerializeException {
|
||||
try {
|
||||
Unsafe unsafe = ReflectionUtil.getUnsafe();
|
||||
T instance = (T) unsafe.allocateInstance(clazz);
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
field.setAccessible(true);
|
||||
if (field.isAnnotationPresent(SerializeIgnore.class)) {
|
||||
continue;
|
||||
}
|
||||
String name = field.getName();
|
||||
if (name.equalsIgnoreCase("this$0")) {
|
||||
continue;
|
||||
}
|
||||
if (!jsonObject.has(name)) {
|
||||
continue;
|
||||
}
|
||||
Object value = jsonObject.get(name);
|
||||
if (value == null) {
|
||||
continue;
|
||||
}
|
||||
Object deserializeValue = deserializeValue(field, field.getType(), value);
|
||||
ReflectionUtil.setFieldUsingUnsafe(field, instance, deserializeValue);
|
||||
}
|
||||
return instance;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new SerializeException(clazz, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Object deserializeValue(Field field, Class clazz0, Object value) throws SerializeException {
|
||||
Class clazz = clazz0;
|
||||
if (WRAPPER_TO_PRIMITIVE.containsKey(clazz)) {
|
||||
clazz = WRAPPER_TO_PRIMITIVE.get(clazz);
|
||||
}
|
||||
if (serializers.containsKey(clazz)) {
|
||||
Serializer serializer = serializers.get(clazz);
|
||||
return serializer.deserialize(value);
|
||||
}
|
||||
if (ISerializable.class.isAssignableFrom(clazz)) {
|
||||
ISerializable iSerializable = (ISerializable) value;
|
||||
JSONObject jsonObject = (JSONObject) value;
|
||||
return iSerializable.deserialize(jsonObject);
|
||||
} else if (clazz.isPrimitive() || clazz.equals(String.class)) {
|
||||
return value;
|
||||
} else if (clazz.isEnum()) {
|
||||
return Enum.valueOf((Class<Enum>) clazz, (String) value);
|
||||
} else if (clazz.isArray()) {
|
||||
JSONArray jsonArray = (JSONArray) value;
|
||||
int length = jsonArray.length();
|
||||
Object object = Array.newInstance(clazz.getComponentType(), length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
Array.set(object, i, deserializeValue(field, clazz.getComponentType(), jsonArray.get(i)));
|
||||
}
|
||||
return object;
|
||||
} else if (List.class.isAssignableFrom(clazz)) {
|
||||
List list = new ArrayList();
|
||||
JSONArray jsonArray = (JSONArray) value;
|
||||
Type genericType = field.getGenericType();
|
||||
Class<?> elementType = (Class<?>) ((ParameterizedType) genericType).getActualTypeArguments()[0];
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
list.add(deserializeValue(field, elementType, jsonArray.get(i)));
|
||||
}
|
||||
return list;
|
||||
} else if (Map.class.isAssignableFrom(clazz)) {
|
||||
Map map = new HashMap();
|
||||
Type genericType = field.getGenericType();
|
||||
Class<?> valueType = (Class<?>) ((ParameterizedType) genericType).getActualTypeArguments()[1];
|
||||
JSONObject jsonObject = (JSONObject) value;
|
||||
for (String key : jsonObject.keySet()) {
|
||||
map.put(key, deserializeValue(field, valueType, jsonObject.get(key)));
|
||||
}
|
||||
return map;
|
||||
} else {
|
||||
return deserialize(clazz, (JSONObject) value);
|
||||
}
|
||||
}
|
||||
|
||||
private static Object serializeValue(Object value) throws SerializeException {
|
||||
Class clazz = value.getClass();
|
||||
if (WRAPPER_TO_PRIMITIVE.containsKey(clazz)) {
|
||||
clazz = WRAPPER_TO_PRIMITIVE.get(clazz);
|
||||
}
|
||||
if (serializers.containsKey(clazz)) {
|
||||
Serializer serializer = serializers.get(clazz);
|
||||
return serializer.serialize(value);
|
||||
}
|
||||
if (ISerializable.class.isAssignableFrom(clazz)) {
|
||||
ISerializable iSerializable = (ISerializable) value;
|
||||
return iSerializable.serialize();
|
||||
} else if (clazz.isPrimitive() || clazz.equals(String.class)) {
|
||||
return value;
|
||||
} else if (clazz.isEnum()) {
|
||||
return ((Enum) value).name();
|
||||
} else if (clazz.isArray()) {
|
||||
Class elementType = clazz.getComponentType();
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
int length = Array.getLength(value);
|
||||
for (int i = 0; i < length; i++) {
|
||||
Object element = Array.get(value, i);
|
||||
jsonArray.put(serializeValue(element));
|
||||
}
|
||||
return jsonArray;
|
||||
} else if (List.class.isAssignableFrom(clazz)) {
|
||||
List list = (List) value;
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
for (Object element : list) {
|
||||
jsonArray.put(serializeValue(element));
|
||||
}
|
||||
return jsonArray;
|
||||
} else if (Map.class.isAssignableFrom(clazz)) {
|
||||
Map map = (Map) value;
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
for (Object key : map.keySet()) {
|
||||
jsonObject.put(key.toString(), serializeValue(map.get(key)));
|
||||
}
|
||||
return jsonObject;
|
||||
} else {
|
||||
return serialize(value);
|
||||
}
|
||||
}
|
||||
|
||||
public static final Map<Class<?>, Class<?>> WRAPPER_TO_PRIMITIVE = new HashMap<>();
|
||||
|
||||
static {
|
||||
WRAPPER_TO_PRIMITIVE.put(Boolean.class, boolean.class);
|
||||
WRAPPER_TO_PRIMITIVE.put(Byte.class, byte.class);
|
||||
WRAPPER_TO_PRIMITIVE.put(Short.class, short.class);
|
||||
WRAPPER_TO_PRIMITIVE.put(Character.class, char.class);
|
||||
WRAPPER_TO_PRIMITIVE.put(Integer.class, int.class);
|
||||
WRAPPER_TO_PRIMITIVE.put(Long.class, long.class);
|
||||
WRAPPER_TO_PRIMITIVE.put(Float.class, float.class);
|
||||
WRAPPER_TO_PRIMITIVE.put(Double.class, double.class);
|
||||
WRAPPER_TO_PRIMITIVE.put(CraftItemStack.class, ItemStack.class);
|
||||
|
||||
registerSerializer(UUID.class, new UUIDSerializer());
|
||||
registerSerializer(ItemStack.class, new ItemStackSerializer());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.io.yutian.elementoriginlib.serialize;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface SerializeIgnore {
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.io.yutian.elementoriginlib.serialize;
|
||||
|
||||
public interface Serializer<T> {
|
||||
|
||||
Object serialize(T value);
|
||||
|
||||
T deserialize(Object value);
|
||||
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
package com.io.yutian.elementoriginlib.serialize.serializers;
|
||||
|
||||
import com.io.yutian.elementoriginlib.serialize.Serializer;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import net.minecraft.nbt.*;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class ItemStackSerializer implements Serializer<ItemStack> {
|
||||
|
||||
@Override
|
||||
public Object serialize(ItemStack value) {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(value);
|
||||
jsonObject.put("id", nmsItemStack.c().d().j().g());
|
||||
jsonObject.put("Count", nmsItemStack.J());
|
||||
NBTTagCompound nbtTagCompound = nmsItemStack.w();
|
||||
JSONObject tagJsonObject = new JSONObject();
|
||||
for (String key : nbtTagCompound.e()) {
|
||||
NBTBase nbtBase = nbtTagCompound.c(key);
|
||||
tagJsonObject.put(key, serializeNBT(nbtBase));
|
||||
}
|
||||
jsonObject.put("tag", tagJsonObject);
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
private Object serializeNBT(NBTBase nbtBase) {
|
||||
byte type = nbtBase.b();
|
||||
switch (type) {
|
||||
case 1:
|
||||
NBTTagByte nbtTagByte = (NBTTagByte) nbtBase;
|
||||
return nbtTagByte.i();
|
||||
case 2:
|
||||
NBTTagShort nbtTagShort = (NBTTagShort) nbtBase;
|
||||
return nbtTagShort.h();
|
||||
case 3:
|
||||
NBTTagInt nbtTagInt = (NBTTagInt) nbtBase;
|
||||
return nbtTagInt.g();
|
||||
case 4:
|
||||
NBTTagLong nbtTagLong = (NBTTagLong) nbtBase;
|
||||
return nbtTagLong.f();
|
||||
case 5:
|
||||
NBTTagFloat nbtTagFloat = (NBTTagFloat) nbtBase;
|
||||
return nbtTagFloat.k();
|
||||
case 6:
|
||||
NBTTagDouble nbtTagDouble = (NBTTagDouble) nbtBase;
|
||||
return nbtTagDouble.j();
|
||||
case 7:
|
||||
NBTTagByteArray tagByteArray = (NBTTagByteArray) nbtBase;
|
||||
return tagByteArray.e();
|
||||
case 8:
|
||||
NBTTagString nbtTagString = (NBTTagString) nbtBase;
|
||||
return nbtTagString.m_();
|
||||
case 9:
|
||||
NBTTagList nbtTagList = (NBTTagList) nbtBase;
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
for (net.minecraft.nbt.NBTBase base : nbtTagList) {
|
||||
jsonArray.put(serializeNBT(base));
|
||||
}
|
||||
return jsonArray;
|
||||
case 10:
|
||||
NBTTagCompound nbtTagCompound = (NBTTagCompound) nbtBase;
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
for (String key : nbtTagCompound.e()) {
|
||||
jsonObject.put(key, serializeNBT(nbtTagCompound.c(key)));
|
||||
}
|
||||
return jsonObject;
|
||||
case 11:
|
||||
NBTTagIntArray nbtTagIntArray = (NBTTagIntArray) nbtBase;
|
||||
return nbtTagIntArray.g();
|
||||
case 12:
|
||||
NBTTagLongArray nbtTagLongArray = (NBTTagLongArray) nbtBase;
|
||||
return nbtTagLongArray.g();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack deserialize(Object value) {
|
||||
JSONObject jsonObject = (JSONObject) value;
|
||||
String arg = jsonObject.toString();
|
||||
NBTTagCompound nbtTagCompound;
|
||||
try {
|
||||
nbtTagCompound = net.minecraft.nbt.MojangsonParser.a(arg);
|
||||
} catch (CommandSyntaxException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
net.minecraft.world.item.ItemStack nmsItemStack = net.minecraft.world.item.ItemStack.a(nbtTagCompound);
|
||||
return CraftItemStack.asCraftMirror(nmsItemStack);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.io.yutian.elementoriginlib.serialize.serializers;
|
||||
|
||||
import com.io.yutian.elementoriginlib.serialize.Serializer;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class UUIDSerializer implements Serializer<UUID> {
|
||||
@Override
|
||||
public Object serialize(UUID value) {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID deserialize(Object value) {
|
||||
return UUID.fromString((String) value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package com.io.yutian.elementoriginlib.sql;
|
||||
import com.io.yutian.elementoriginlib.sql.api.SQLManager;
|
||||
import com.io.yutian.elementoriginlib.sql.api.SQLQuery;
|
||||
import com.io.yutian.elementoriginlib.sql.api.util.TimeDateUtils;
|
||||
import com.io.yutian.elementoriginlib.sql.manager.SQLManagerImpl;
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
public class SQLHelper {
|
||||
|
||||
public static SQLManagerImpl createManager(
|
||||
@NotNull String driver, @NotNull String url,
|
||||
@NotNull String username, @Nullable String password) {
|
||||
HikariConfig config = new HikariConfig();
|
||||
config.setDriverClassName(driver);
|
||||
config.setJdbcUrl(url);
|
||||
config.setUsername(username);
|
||||
config.setPassword(password);
|
||||
return createManager(config);
|
||||
}
|
||||
|
||||
public static SQLManagerImpl createManager(@NotNull Properties properties) {
|
||||
return createManager(new HikariConfig(properties));
|
||||
}
|
||||
|
||||
public static SQLManagerImpl createManager(@NotNull HikariConfig config) {
|
||||
return new SQLManagerImpl(new HikariDataSource(config));
|
||||
}
|
||||
|
||||
public static void shutdownManager(SQLManager manager, boolean forceClose, boolean outputActiveQuery) {
|
||||
if (!manager.getActiveQuery().isEmpty()) {
|
||||
manager.getLogger().warn("There are " + manager.getActiveQuery().size() + " connections still running");
|
||||
for (SQLQuery value : manager.getActiveQuery().values()) {
|
||||
if (outputActiveQuery) {
|
||||
manager.getLogger().warn(String.format("#%s -> %s", value.getAction().getShortID(), value.getSQLContent()));
|
||||
manager.getLogger().warn(String.format("- execute at %s", TimeDateUtils.getTimeString(value.getExecuteTime())));
|
||||
}
|
||||
if (forceClose) value.close();
|
||||
}
|
||||
}
|
||||
if (manager.getDataSource() instanceof HikariDataSource) {
|
||||
//Close hikari pool
|
||||
((HikariDataSource) manager.getDataSource()).close();
|
||||
}
|
||||
}
|
||||
|
||||
public static void shutdownManager(SQLManager manager) {
|
||||
shutdownManager(manager, true, manager.isDebugMode());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
package com.io.yutian.elementoriginlib.sql.action;
|
||||
|
||||
import com.io.yutian.elementoriginlib.sql.api.SQLAction;
|
||||
import com.io.yutian.elementoriginlib.sql.api.function.SQLExceptionHandler;
|
||||
import com.io.yutian.elementoriginlib.sql.api.function.SQLFunction;
|
||||
import com.io.yutian.elementoriginlib.sql.api.function.SQLHandler;
|
||||
import com.io.yutian.elementoriginlib.sql.manager.SQLManagerImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public abstract class AbstractSQLAction<T> implements SQLAction<T> {
|
||||
|
||||
protected final @NotNull String sqlContent;
|
||||
private final @NotNull SQLManagerImpl sqlManager;
|
||||
private final @NotNull UUID uuid;
|
||||
private final long createNanoTime;
|
||||
|
||||
public AbstractSQLAction(@NotNull SQLManagerImpl manager, @NotNull String sql) {
|
||||
this(manager, sql, System.nanoTime());
|
||||
}
|
||||
|
||||
public AbstractSQLAction(@NotNull SQLManagerImpl manager, @NotNull String sql, @NotNull UUID uuid) {
|
||||
this(manager, sql, uuid, System.nanoTime());
|
||||
}
|
||||
|
||||
public AbstractSQLAction(@NotNull SQLManagerImpl manager, @NotNull String sql, long createNanoTime) {
|
||||
this(manager, sql, UUID.randomUUID(), createNanoTime);
|
||||
}
|
||||
|
||||
public AbstractSQLAction(@NotNull SQLManagerImpl manager, @NotNull String sql,
|
||||
@NotNull UUID uuid, long createNanoTime) {
|
||||
Objects.requireNonNull(manager);
|
||||
Objects.requireNonNull(sql);
|
||||
Objects.requireNonNull(uuid);
|
||||
this.sqlManager = manager;
|
||||
this.sqlContent = sql;
|
||||
this.uuid = uuid;
|
||||
this.createNanoTime = createNanoTime;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public @NotNull UUID getActionUUID() {
|
||||
return this.uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getShortID() {
|
||||
return getActionUUID().toString().substring(0, 8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCreateTime(TimeUnit unit) {
|
||||
return unit.convert(createNanoTime, TimeUnit.NANOSECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getSQLContent() {
|
||||
return this.sqlContent.trim();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull SQLManagerImpl getManager() {
|
||||
return this.sqlManager;
|
||||
}
|
||||
|
||||
protected void debugMessage(List<Object[]> params) {
|
||||
if (getManager().isDebugMode()) {
|
||||
try {
|
||||
getManager().getDebugHandler().beforeExecute(this, params);
|
||||
} catch (Exception exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("FutureReturnValueIgnored")
|
||||
public void executeAsync(SQLHandler<T> success, SQLExceptionHandler failure) {
|
||||
getManager().getExecutorPool().submit(() -> {
|
||||
try {
|
||||
T returnedValue = execute();
|
||||
if (success != null) success.accept(returnedValue);
|
||||
} catch (SQLException e) {
|
||||
handleException(failure, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull <R> CompletableFuture<R> executeFuture(@NotNull SQLFunction<T, R> handler) {
|
||||
CompletableFuture<R> future = new CompletableFuture<>();
|
||||
executeAsync((t -> future.complete(handler.apply(t))), (e, q) -> future.completeExceptionally(e));
|
||||
return future;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
package com.io.yutian.elementoriginlib.sql.action;
|
||||
|
||||
import com.io.yutian.elementoriginlib.sql.api.action.PreparedSQLUpdateBatchAction;
|
||||
import com.io.yutian.elementoriginlib.sql.manager.SQLManagerImpl;
|
||||
import com.io.yutian.elementoriginlib.sql.util.StatementUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class PreparedSQLBatchUpdateActionImpl<T extends Number>
|
||||
extends AbstractSQLAction<List<T>>
|
||||
implements PreparedSQLUpdateBatchAction<T> {
|
||||
|
||||
boolean returnKeys = false;
|
||||
@NotNull List<Object[]> allParams = new ArrayList<>();
|
||||
|
||||
protected final @NotNull Class<T> numberClass;
|
||||
|
||||
public PreparedSQLBatchUpdateActionImpl(@NotNull SQLManagerImpl manager, @NotNull Class<T> numberClass,
|
||||
@NotNull String sql) {
|
||||
super(manager, sql);
|
||||
this.numberClass = numberClass;
|
||||
this.allParams = new ArrayList<>();
|
||||
}
|
||||
|
||||
public PreparedSQLBatchUpdateActionImpl(@NotNull SQLManagerImpl manager, @NotNull Class<T> numberClass,
|
||||
@NotNull UUID uuid, @NotNull String sql) {
|
||||
super(manager, sql, uuid);
|
||||
this.numberClass = numberClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedSQLBatchUpdateActionImpl<T> setAllParams(Iterable<Object[]> allParams) {
|
||||
List<Object[]> paramsList = new ArrayList<>();
|
||||
allParams.forEach(paramsList::add);
|
||||
this.allParams = paramsList;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedSQLBatchUpdateActionImpl<T> addParamsBatch(Object... params) {
|
||||
this.allParams.add(params);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedSQLBatchUpdateActionImpl<T> returnGeneratedKeys() {
|
||||
this.returnKeys = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <N extends Number> PreparedSQLBatchUpdateActionImpl<N> returnGeneratedKeys(Class<N> keyTypeClass) {
|
||||
return new PreparedSQLBatchUpdateActionImpl<>(getManager(), keyTypeClass, getActionUUID(), getSQLContent())
|
||||
.setAllParams(allParams).returnGeneratedKeys();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<T> execute() throws SQLException {
|
||||
debugMessage(allParams);
|
||||
|
||||
try (Connection connection = getManager().getConnection()) {
|
||||
try (PreparedStatement statement = StatementUtil.createPrepareStatementBatch(
|
||||
connection, getSQLContent(), allParams, returnKeys
|
||||
)) {
|
||||
int[] executed = statement.executeBatch();
|
||||
|
||||
if (!returnKeys) {
|
||||
return Arrays.stream(executed).mapToObj(numberClass::cast).collect(Collectors.toList());
|
||||
} else {
|
||||
try (ResultSet resultSet = statement.getGeneratedKeys()) {
|
||||
List<T> generatedKeys = new ArrayList<>();
|
||||
while (resultSet.next()) {
|
||||
generatedKeys.add(resultSet.getObject(1, numberClass));
|
||||
}
|
||||
return generatedKeys;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package com.io.yutian.elementoriginlib.sql.action;
|
||||
|
||||
import com.io.yutian.elementoriginlib.sql.api.action.PreparedSQLUpdateAction;
|
||||
import com.io.yutian.elementoriginlib.sql.api.action.SQLUpdateAction;
|
||||
import com.io.yutian.elementoriginlib.sql.manager.SQLManagerImpl;
|
||||
import com.io.yutian.elementoriginlib.sql.util.StatementUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PreparedSQLUpdateActionImpl<T extends Number>
|
||||
extends SQLUpdateActionImpl<T>
|
||||
implements PreparedSQLUpdateAction<T> {
|
||||
|
||||
Object[] params;
|
||||
|
||||
public PreparedSQLUpdateActionImpl(@NotNull SQLManagerImpl manager, @NotNull Class<T> numberClass,
|
||||
@NotNull String sql) {
|
||||
this(manager, numberClass, sql, (Object[]) null);
|
||||
}
|
||||
|
||||
public PreparedSQLUpdateActionImpl(@NotNull SQLManagerImpl manager, @NotNull Class<T> numberClass,
|
||||
@NotNull String sql, @Nullable List<Object> params) {
|
||||
this(manager, numberClass, sql, params == null ? null : params.toArray());
|
||||
}
|
||||
|
||||
public PreparedSQLUpdateActionImpl(@NotNull SQLManagerImpl manager, @NotNull Class<T> numberClass,
|
||||
@NotNull String sql, @Nullable Object[] params) {
|
||||
super(manager, numberClass, sql);
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
public PreparedSQLUpdateActionImpl(@NotNull SQLManagerImpl manager, @NotNull Class<T> numberClass,
|
||||
@NotNull UUID uuid, @NotNull String sql,
|
||||
Object[] params) {
|
||||
super(manager, numberClass, uuid, sql);
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedSQLUpdateActionImpl<T> setParams(Object... params) {
|
||||
this.params = params;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedSQLUpdateActionImpl<T> setParams(@Nullable Iterable<Object> params) {
|
||||
if (params == null) {
|
||||
return setParams((Object[]) null);
|
||||
} else {
|
||||
List<Object> paramsList = new ArrayList<>();
|
||||
params.forEach(paramsList::add);
|
||||
return setParams(paramsList.toArray());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull T execute() throws SQLException {
|
||||
debugMessage(Collections.singletonList(params));
|
||||
|
||||
try (Connection connection = getManager().getConnection()) {
|
||||
|
||||
try (PreparedStatement statement = StatementUtil.createPrepareStatement(
|
||||
connection, getSQLContent(), params, returnGeneratedKeys
|
||||
)) {
|
||||
|
||||
int changes = statement.executeUpdate();
|
||||
if (!returnGeneratedKeys) return numberClass.cast(changes);
|
||||
else {
|
||||
try (ResultSet resultSet = statement.getGeneratedKeys()) {
|
||||
return resultSet.next() ? resultSet.getObject(1, numberClass) : numberClass.cast(0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public <N extends Number> SQLUpdateAction<N> returnGeneratedKey(Class<N> keyTypeClass) {
|
||||
PreparedSQLUpdateActionImpl<N> newAction = new PreparedSQLUpdateActionImpl<>(getManager(), keyTypeClass, getActionUUID(), getSQLContent(), params);
|
||||
newAction.returnGeneratedKey();
|
||||
return newAction;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package com.io.yutian.elementoriginlib.sql.action;
|
||||
|
||||
import com.io.yutian.elementoriginlib.sql.api.action.SQLUpdateAction;
|
||||
import com.io.yutian.elementoriginlib.sql.manager.SQLManagerImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.UUID;
|
||||
|
||||
public class SQLUpdateActionImpl<T extends Number>
|
||||
extends AbstractSQLAction<T>
|
||||
implements SQLUpdateAction<T> {
|
||||
|
||||
protected final @NotNull Class<T> numberClass;
|
||||
|
||||
protected boolean returnGeneratedKeys = false;
|
||||
|
||||
public SQLUpdateActionImpl(@NotNull SQLManagerImpl manager, @NotNull Class<T> numberClass,
|
||||
@NotNull String sql) {
|
||||
super(manager, sql);
|
||||
this.numberClass = numberClass;
|
||||
}
|
||||
|
||||
public SQLUpdateActionImpl(@NotNull SQLManagerImpl manager, @NotNull Class<T> numberClass,
|
||||
@NotNull UUID uuid, @NotNull String sql) {
|
||||
super(manager, sql, uuid);
|
||||
this.numberClass = numberClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull T execute() throws SQLException {
|
||||
debugMessage(new ArrayList<>());
|
||||
|
||||
try (Connection connection = getManager().getConnection()) {
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
|
||||
if (!returnGeneratedKeys) {
|
||||
return numberClass.cast(statement.executeUpdate(getSQLContent()));
|
||||
} else {
|
||||
statement.executeUpdate(getSQLContent(), Statement.RETURN_GENERATED_KEYS);
|
||||
|
||||
try (ResultSet resultSet = statement.getGeneratedKeys()) {
|
||||
return resultSet.next() ? resultSet.getObject(1, numberClass) : numberClass.cast(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLUpdateAction<T> returnGeneratedKey() {
|
||||
this.returnGeneratedKeys = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <N extends Number> SQLUpdateAction<N> returnGeneratedKey(Class<N> keyTypeClass) {
|
||||
return new SQLUpdateActionImpl<>(getManager(), keyTypeClass, getActionUUID(), getSQLContent()).returnGeneratedKey();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package com.io.yutian.elementoriginlib.sql.action;
|
||||
|
||||
import com.io.yutian.elementoriginlib.sql.api.action.SQLUpdateBatchAction;
|
||||
import com.io.yutian.elementoriginlib.sql.manager.SQLManagerImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class SQLUpdateBatchActionImpl
|
||||
extends AbstractSQLAction<List<Integer>>
|
||||
implements SQLUpdateBatchAction {
|
||||
|
||||
protected final List<String> sqlContents = new ArrayList<>();
|
||||
|
||||
public SQLUpdateBatchActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql) {
|
||||
super(manager, sql);
|
||||
this.sqlContents.add(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<String> getSQLContents() {
|
||||
return this.sqlContents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLUpdateBatchAction addBatch(@NotNull String sql) {
|
||||
Objects.requireNonNull(sql, "sql could not be null");
|
||||
this.sqlContents.add(sql);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<Integer> execute() throws SQLException {
|
||||
debugMessage(new ArrayList<>());
|
||||
|
||||
try (Connection connection = getManager().getConnection()) {
|
||||
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
|
||||
for (String content : this.sqlContents) {
|
||||
statement.addBatch(content);
|
||||
}
|
||||
|
||||
int[] executed = statement.executeBatch();
|
||||
|
||||
return Arrays.stream(executed).boxed().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package com.io.yutian.elementoriginlib.sql.action.query;
|
||||
|
||||
import com.io.yutian.elementoriginlib.sql.api.action.query.PreparedQueryAction;
|
||||
import com.io.yutian.elementoriginlib.sql.manager.SQLManagerImpl;
|
||||
import com.io.yutian.elementoriginlib.sql.util.StatementUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class PreparedQueryActionImpl extends QueryActionImpl implements PreparedQueryAction {
|
||||
|
||||
Consumer<PreparedStatement> handler;
|
||||
Object[] params;
|
||||
|
||||
public PreparedQueryActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql) {
|
||||
super(manager, sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedQueryActionImpl setParams(@Nullable Object... params) {
|
||||
this.params = params;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedQueryActionImpl setParams(@Nullable Iterable<Object> params) {
|
||||
if (params == null) {
|
||||
return setParams((Object[]) null);
|
||||
} else {
|
||||
List<Object> paramsList = new ArrayList<>();
|
||||
params.forEach(paramsList::add);
|
||||
return setParams(paramsList.toArray());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedQueryActionImpl handleStatement(@Nullable Consumer<PreparedStatement> statement) {
|
||||
this.handler = statement;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public @NotNull SQLQueryImpl execute() throws SQLException {
|
||||
debugMessage(Collections.singletonList(params));
|
||||
|
||||
Connection connection = getManager().getConnection();
|
||||
PreparedStatement preparedStatement;
|
||||
try {
|
||||
if (handler == null) {
|
||||
preparedStatement = StatementUtil.createPrepareStatement(connection, getSQLContent(), this.params);
|
||||
} else {
|
||||
preparedStatement = connection.prepareStatement(getSQLContent());
|
||||
handler.accept(preparedStatement);
|
||||
}
|
||||
} catch (SQLException exception) {
|
||||
connection.close();
|
||||
throw exception;
|
||||
}
|
||||
|
||||
try {
|
||||
SQLQueryImpl query = new SQLQueryImpl(
|
||||
getManager(), this,
|
||||
connection, preparedStatement,
|
||||
preparedStatement.executeQuery()
|
||||
);
|
||||
getManager().getActiveQuery().put(getActionUUID(), query);
|
||||
return query;
|
||||
} catch (SQLException exception) {
|
||||
preparedStatement.close();
|
||||
connection.close();
|
||||
throw exception;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package com.io.yutian.elementoriginlib.sql.action.query;
|
||||
|
||||
import com.io.yutian.elementoriginlib.sql.action.AbstractSQLAction;
|
||||
import com.io.yutian.elementoriginlib.sql.api.SQLQuery;
|
||||
import com.io.yutian.elementoriginlib.sql.api.action.query.QueryAction;
|
||||
import com.io.yutian.elementoriginlib.sql.api.function.SQLExceptionHandler;
|
||||
import com.io.yutian.elementoriginlib.sql.api.function.SQLHandler;
|
||||
import com.io.yutian.elementoriginlib.sql.manager.SQLManagerImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class QueryActionImpl extends AbstractSQLAction<SQLQuery> implements QueryAction {
|
||||
|
||||
public QueryActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql) {
|
||||
super(manager, sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull SQLQueryImpl execute() throws SQLException {
|
||||
debugMessage(new ArrayList<>());
|
||||
|
||||
Connection connection = getManager().getConnection();
|
||||
Statement statement;
|
||||
|
||||
try {
|
||||
statement = connection.createStatement();
|
||||
} catch (SQLException ex) {
|
||||
connection.close();
|
||||
throw ex;
|
||||
}
|
||||
|
||||
try {
|
||||
SQLQueryImpl query = new SQLQueryImpl(
|
||||
getManager(), this,
|
||||
connection, statement,
|
||||
statement.executeQuery(getSQLContent())
|
||||
);
|
||||
getManager().getActiveQuery().put(getActionUUID(), query);
|
||||
|
||||
return query;
|
||||
} catch (SQLException exception) {
|
||||
statement.close();
|
||||
connection.close();
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void executeAsync(SQLHandler<SQLQuery> success, SQLExceptionHandler failure) {
|
||||
getManager().getExecutorPool().submit(() -> {
|
||||
try (SQLQueryImpl query = execute()) {
|
||||
if (success != null) success.accept(query);
|
||||
} catch (SQLException exception) {
|
||||
handleException(failure, exception);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package com.io.yutian.elementoriginlib.sql.action.query;
|
||||
|
||||
import com.io.yutian.elementoriginlib.sql.api.SQLQuery;
|
||||
import com.io.yutian.elementoriginlib.sql.manager.SQLManagerImpl;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class SQLQueryImpl implements SQLQuery {
|
||||
|
||||
protected final long executeTime;
|
||||
|
||||
protected final SQLManagerImpl sqlManager;
|
||||
protected final Connection connection;
|
||||
protected final Statement statement;
|
||||
protected final ResultSet resultSet;
|
||||
protected QueryActionImpl queryAction;
|
||||
|
||||
public SQLQueryImpl(
|
||||
SQLManagerImpl sqlManager, QueryActionImpl queryAction,
|
||||
Connection connection, Statement statement, ResultSet resultSet
|
||||
) {
|
||||
this(sqlManager, queryAction, connection, statement, resultSet, System.nanoTime());
|
||||
}
|
||||
|
||||
public SQLQueryImpl(
|
||||
SQLManagerImpl sqlManager, QueryActionImpl queryAction,
|
||||
Connection connection, Statement statement, ResultSet resultSet,
|
||||
long executeTime
|
||||
) {
|
||||
this.executeTime = executeTime;
|
||||
this.sqlManager = sqlManager;
|
||||
this.queryAction = queryAction;
|
||||
this.connection = connection;
|
||||
this.statement = statement;
|
||||
this.resultSet = resultSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getExecuteTime(TimeUnit timeUnit) {
|
||||
return timeUnit.convert(this.executeTime, TimeUnit.NANOSECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLManagerImpl getManager() {
|
||||
return this.sqlManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryActionImpl getAction() {
|
||||
return this.queryAction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet getResultSet() {
|
||||
return this.resultSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSQLContent() {
|
||||
return getAction().getSQLContent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
if (getResultSet() != null && !getResultSet().isClosed()) getResultSet().close();
|
||||
if (getStatement() != null && !getStatement().isClosed()) getStatement().close();
|
||||
if (getConnection() != null && !getConnection().isClosed()) getConnection().close();
|
||||
|
||||
if (getManager().isDebugMode()) {
|
||||
try {
|
||||
getManager().getDebugHandler().afterQuery(this, getExecuteTime(TimeUnit.NANOSECONDS), System.nanoTime());
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
getManager().getActiveQuery().remove(getAction().getActionUUID());
|
||||
} catch (SQLException e) {
|
||||
getAction().handleException(getAction().defaultExceptionHandler(), e);
|
||||
}
|
||||
this.queryAction = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statement getStatement() {
|
||||
return this.statement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() {
|
||||
return this.connection;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,254 @@
|
|||
package com.io.yutian.elementoriginlib.sql.api;
|
||||
|
||||
import com.io.yutian.elementoriginlib.sql.api.function.SQLExceptionHandler;
|
||||
import com.io.yutian.elementoriginlib.sql.api.function.SQLFunction;
|
||||
import com.io.yutian.elementoriginlib.sql.api.function.SQLHandler;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* SQLAction 是用于承载SQL语句并进行处理、返回的基本类。
|
||||
*
|
||||
* <ul>
|
||||
* <li>同步执行 {@link #execute()}, {@link #execute(SQLFunction, SQLExceptionHandler)}
|
||||
* <br>同步执行方法中有会抛出异常的方法与不抛出异常的方法,
|
||||
* <br>若选择不抛出异常,则返回值可能为空,需要特殊处理。</li>
|
||||
*
|
||||
* <li>异步执行 {@link #executeAsync(SQLHandler, SQLExceptionHandler)}
|
||||
* <br>异步执行时将提供成功与异常两种处理方式
|
||||
* <br>可自行选择是否对数据或异常进行处理
|
||||
* <br>默认的异常处理器为 {@link #defaultExceptionHandler()}
|
||||
* <br>若有特殊需要,可通过{@link #setExceptionHandler(SQLExceptionHandler)} 方法修改默认的处理器</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param <T> 需要返回的类型
|
||||
* @author CarmJos
|
||||
* @since 0.0.1
|
||||
*/
|
||||
public interface SQLAction<T> {
|
||||
|
||||
/**
|
||||
* 得到该Action的UUID
|
||||
*
|
||||
* @return UUID
|
||||
*/
|
||||
@NotNull UUID getActionUUID();
|
||||
|
||||
/**
|
||||
* 得到短八位格式的UUID
|
||||
*
|
||||
* @return UUID(8)
|
||||
*/
|
||||
@NotNull String getShortID();
|
||||
|
||||
/**
|
||||
* 得到该Action的创建时间。
|
||||
* <br>注意,此处获得的时间非时间戳毫秒数,仅用于计算耗时。
|
||||
*
|
||||
* @return 创建时间 (毫秒)
|
||||
*/
|
||||
default long getCreateTime() {
|
||||
return getCreateTime(TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到该Action的创建时间
|
||||
* <br>注意,此处获得的时间非时间戳毫秒数,仅用于计算耗时。
|
||||
*
|
||||
* @param unit 时间单位
|
||||
* @return 创建时间
|
||||
*/
|
||||
long getCreateTime(TimeUnit unit);
|
||||
|
||||
/**
|
||||
* 得到该Action所要执行的源SQL语句
|
||||
*
|
||||
* @return 源SQL语句
|
||||
*/
|
||||
@NotNull String getSQLContent();
|
||||
|
||||
/**
|
||||
* 得到该Action所要执行的源SQL语句列表。
|
||||
*
|
||||
* @return 源SQL语句列表
|
||||
*/
|
||||
default @NotNull List<String> getSQLContents() {
|
||||
return Collections.singletonList(getSQLContent());
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到承载该Action的对应{@link SQLManager}
|
||||
*
|
||||
* @return {@link SQLManager}
|
||||
*/
|
||||
@NotNull SQLManager getManager();
|
||||
|
||||
/**
|
||||
* 执行该Action对应的SQL语句
|
||||
*
|
||||
* @return 指定数据类型
|
||||
* @throws SQLException 当SQL操作出现问题时抛出
|
||||
*/
|
||||
@NotNull T execute() throws SQLException;
|
||||
|
||||
|
||||
/**
|
||||
* 执行语句并返回值
|
||||
*
|
||||
* @param exceptionHandler 异常处理器 默认为 {@link #defaultExceptionHandler()}
|
||||
* @return 指定类型数据
|
||||
*/
|
||||
@Nullable
|
||||
default T execute(@Nullable SQLExceptionHandler exceptionHandler) {
|
||||
return execute(t -> t, exceptionHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行语句并处理返回值
|
||||
*
|
||||
* @param function 处理方法
|
||||
* @param exceptionHandler 异常处理器 默认为 {@link #defaultExceptionHandler()}
|
||||
* @param <R> 需要返回的内容
|
||||
* @return 指定类型数据
|
||||
*/
|
||||
@Nullable
|
||||
default <R> R execute(@NotNull SQLFunction<T, R> function,
|
||||
@Nullable SQLExceptionHandler exceptionHandler) {
|
||||
return execute(function, null, exceptionHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行语句并处理返回值
|
||||
*
|
||||
* @param function 处理方法
|
||||
* @param defaultResult 默认结果,若处理后的结果为null,则返回该值
|
||||
* @param exceptionHandler 异常处理器 默认为 {@link #defaultExceptionHandler()}
|
||||
* @param <R> 需要返回的内容
|
||||
* @return 指定类型数据
|
||||
*/
|
||||
@Nullable
|
||||
@Contract("_,!null,_ -> !null")
|
||||
default <R> R execute(@NotNull SQLFunction<T, R> function,
|
||||
@Nullable R defaultResult,
|
||||
@Nullable SQLExceptionHandler exceptionHandler) {
|
||||
try {
|
||||
return executeFunction(function, defaultResult);
|
||||
} catch (SQLException exception) {
|
||||
handleException(exceptionHandler, exception);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行语句并处理返回值
|
||||
*
|
||||
* @param function 处理方法
|
||||
* @param <R> 需要返回的内容
|
||||
* @return 指定类型数据
|
||||
* @throws SQLException 当SQL操作出现问题时抛出
|
||||
*/
|
||||
@Nullable
|
||||
default <R> R executeFunction(@NotNull SQLFunction<@NotNull T, R> function) throws SQLException {
|
||||
return executeFunction(function, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行语句并处理返回值
|
||||
*
|
||||
* @param function 处理方法
|
||||
* @param defaultResult 默认结果,若处理后的结果为null,则返回该值
|
||||
* @param <R> 需要返回的内容
|
||||
* @return 指定类型数据
|
||||
* @throws SQLException 当SQL操作出现问题时抛出
|
||||
*/
|
||||
@Nullable
|
||||
@Contract("_,!null -> !null")
|
||||
default <R> R executeFunction(@NotNull SQLFunction<@NotNull T, R> function,
|
||||
@Nullable R defaultResult) throws SQLException {
|
||||
try {
|
||||
R result = function.apply(execute());
|
||||
return result == null ? defaultResult : result;
|
||||
} catch (SQLException exception) {
|
||||
throw new SQLException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步执行SQL语句,采用默认异常处理,无需返回值。
|
||||
*/
|
||||
default void executeAsync() {
|
||||
executeAsync(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步执行SQL语句
|
||||
*
|
||||
* @param success 成功时的操作
|
||||
*/
|
||||
default void executeAsync(@Nullable SQLHandler<T> success) {
|
||||
executeAsync(success, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步执行SQL语句
|
||||
*
|
||||
* @param success 成功时的操作
|
||||
* @param failure 异常处理器 默认为 {@link SQLAction#defaultExceptionHandler()}
|
||||
*/
|
||||
void executeAsync(@Nullable SQLHandler<T> success,
|
||||
@Nullable SQLExceptionHandler failure);
|
||||
|
||||
/**
|
||||
* 以异步Future方式执行SQL语句。
|
||||
*
|
||||
* @return 异步执行的Future实例,可通过 {@link Future#get()} 阻塞并等待结果。
|
||||
*/
|
||||
default @NotNull CompletableFuture<Void> executeFuture() {
|
||||
return executeFuture((t -> null));
|
||||
}
|
||||
|
||||
/**
|
||||
* 以异步Future方式执行SQL语句。
|
||||
*
|
||||
* @return 异步执行的Future实例,可通过 {@link Future#get()} 阻塞并等待结果。
|
||||
*/
|
||||
<R> @NotNull CompletableFuture<R> executeFuture(@NotNull SQLFunction<T, R> handler);
|
||||
|
||||
default void handleException(@Nullable SQLExceptionHandler handler, SQLException exception) {
|
||||
if (handler == null) handler = defaultExceptionHandler();
|
||||
handler.accept(exception, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取管理器提供的默认异常处理器。
|
||||
* 若未使用过 {@link #setExceptionHandler(SQLExceptionHandler)} 方法,
|
||||
* 则默认返回 {@link SQLExceptionHandler#detailed(Logger)} 。
|
||||
*
|
||||
* @return {@link SQLExceptionHandler}
|
||||
*/
|
||||
default SQLExceptionHandler defaultExceptionHandler() {
|
||||
return getManager().getExceptionHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设定通用的异常处理器。
|
||||
* <br> 在使用 {@link #execute(SQLExceptionHandler)} 等相关方法时,若传入的处理器为null,则会采用此处理器。
|
||||
* <br> 若该方法传入参数为 null,则会使用 {@link #defaultExceptionHandler()} 。
|
||||
*
|
||||
* @param handler 异常处理器
|
||||
*/
|
||||
default void setExceptionHandler(@Nullable SQLExceptionHandler handler) {
|
||||
getManager().setExceptionHandler(handler);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package com.io.yutian.elementoriginlib.sql.api;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* SQLBuilder 是用于构建SQL语句以生成SQLAction执行操作的中间类。
|
||||
* <br>其连接了{@link SQLManager} 与 {@link SQLAction} ,避免大量的代码堆积
|
||||
* <br>也是本接口的核心功能所在
|
||||
*
|
||||
* @author CarmJos
|
||||
*/
|
||||
public interface SQLBuilder {
|
||||
|
||||
static @NotNull String withBackQuote(@NotNull String str) {
|
||||
str = str.trim();
|
||||
return !str.isEmpty() && str.charAt(0) == '`' && str.charAt(str.length() - 1) == '`' ? str : "`" + str + "`";
|
||||
}
|
||||
|
||||
static @NotNull String withQuote(@NotNull String str) {
|
||||
str = str.trim();
|
||||
return !str.isEmpty() && str.charAt(0) == '\'' && str.charAt(str.length() - 1) == '\'' ? str : "'" + str + "'";
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到承载该Builder的对应{@link SQLManager}
|
||||
*
|
||||
* @return {@link SQLManager}
|
||||
*/
|
||||
@NotNull SQLManager getManager();
|
||||
|
||||
}
|
|
@ -0,0 +1,316 @@
|
|||
package com.io.yutian.elementoriginlib.sql.api;
|
||||
|
||||
import com.io.yutian.elementoriginlib.sql.api.action.PreparedSQLUpdateAction;
|
||||
import com.io.yutian.elementoriginlib.sql.api.action.PreparedSQLUpdateBatchAction;
|
||||
import com.io.yutian.elementoriginlib.sql.api.action.SQLUpdateAction;
|
||||
import com.io.yutian.elementoriginlib.sql.api.action.SQLUpdateBatchAction;
|
||||
import com.io.yutian.elementoriginlib.sql.api.builder.*;
|
||||
import com.io.yutian.elementoriginlib.sql.api.function.SQLBiFunction;
|
||||
import com.io.yutian.elementoriginlib.sql.api.function.SQLDebugHandler;
|
||||
import com.io.yutian.elementoriginlib.sql.api.function.SQLExceptionHandler;
|
||||
import com.io.yutian.elementoriginlib.sql.api.function.SQLFunction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* SQLManager 是EasySQL的核心类,用于管理数据库连接,提供数据库操作的方法。
|
||||
*
|
||||
* @author CarmJos
|
||||
*/
|
||||
public interface SQLManager {
|
||||
|
||||
Logger getLogger();
|
||||
|
||||
boolean isDebugMode();
|
||||
|
||||
|
||||
/**
|
||||
* 获取用于执行 {@link SQLAction#executeAsync()} 的线程池。
|
||||
* <br> 默认线程池为 {@link #defaultExecutorPool(String)} 。
|
||||
*
|
||||
* @return {@link ExecutorService}
|
||||
*/
|
||||
@NotNull ExecutorService getExecutorPool();
|
||||
|
||||
/**
|
||||
* 设定用于执行 {@link SQLAction#executeAsync()} 的线程池.
|
||||
* <br> 默认线程池为 {@link #defaultExecutorPool(String)} 。
|
||||
*
|
||||
* @param executorPool {@link ExecutorService}
|
||||
*/
|
||||
void setExecutorPool(@NotNull ExecutorService executorPool);
|
||||
|
||||
static ExecutorService defaultExecutorPool(String threadName) {
|
||||
return Executors.newFixedThreadPool(4, r -> {
|
||||
Thread thread = new Thread(r, threadName);
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 设定是否启用调试模式。
|
||||
* 启用调试模式后,会在每次执行SQL语句时,调用 {@link #getDebugHandler()} 来输出调试信息。
|
||||
*
|
||||
* @param debugMode 是否启用调试模式
|
||||
*/
|
||||
void setDebugMode(@NotNull Supplier<@NotNull Boolean> debugMode);
|
||||
|
||||
/**
|
||||
* 设定是否启用调试模式。
|
||||
* 启用调试模式后,会在每次执行SQL语句时,调用 {@link #getDebugHandler()} 来输出调试信息。
|
||||
*
|
||||
* @param enable 是否启用调试模式
|
||||
*/
|
||||
default void setDebugMode(boolean enable) {
|
||||
setDebugMode(() -> enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取调试处理器,用于处理调试信息。
|
||||
*
|
||||
* @return {@link SQLDebugHandler}
|
||||
*/
|
||||
@NotNull SQLDebugHandler getDebugHandler();
|
||||
|
||||
/**
|
||||
* 设定调试处理器,默认为 {@link SQLDebugHandler#defaultHandler(Logger)} 。
|
||||
*
|
||||
* @param debugHandler {@link SQLDebugHandler}
|
||||
*/
|
||||
void setDebugHandler(@NotNull SQLDebugHandler debugHandler);
|
||||
|
||||
/**
|
||||
* 得到连接池源
|
||||
*
|
||||
* @return DataSource
|
||||
*/
|
||||
@NotNull DataSource getDataSource();
|
||||
|
||||
/**
|
||||
* 得到一个数据库连接实例
|
||||
*
|
||||
* @return Connection
|
||||
* @throws SQLException 见 {@link DataSource#getConnection()}
|
||||
*/
|
||||
@NotNull Connection getConnection() throws SQLException;
|
||||
|
||||
/**
|
||||
* 得到正使用的查询。
|
||||
*
|
||||
* @return 查询列表
|
||||
*/
|
||||
@NotNull Map<UUID, SQLQuery> getActiveQuery();
|
||||
|
||||
/**
|
||||
* 获取改管理器提供的默认异常处理器。
|
||||
* 若未使用过 {@link #setExceptionHandler(SQLExceptionHandler)} 方法,
|
||||
* 则默认返回 {@link SQLExceptionHandler#detailed(Logger)} 。
|
||||
*
|
||||
* @return {@link SQLExceptionHandler}
|
||||
*/
|
||||
@NotNull SQLExceptionHandler getExceptionHandler();
|
||||
|
||||
/**
|
||||
* 设定通用的异常处理器。
|
||||
* <br> 在使用 {@link SQLAction#execute(SQLExceptionHandler)} 等相关方法时,若传入的处理器为null,则会采用此处理器。
|
||||
* <br> 若该方法传入参数为 null,则会使用 {@link SQLExceptionHandler#detailed(Logger)} 。
|
||||
*
|
||||
* @param handler 异常处理器
|
||||
*/
|
||||
void setExceptionHandler(@Nullable SQLExceptionHandler handler);
|
||||
|
||||
/**
|
||||
* 执行一条不需要返回结果的SQL语句(多用于UPDATE、REPLACE、DELETE方法)
|
||||
* 该方法使用 Statement 实现,请注意SQL注入风险!
|
||||
*
|
||||
* @param sql SQL语句内容
|
||||
* @return 更新的行数
|
||||
* @see SQLUpdateAction
|
||||
*/
|
||||
@Nullable Integer executeSQL(String sql);
|
||||
|
||||
/**
|
||||
* 执行一条不需要返回结果的预处理SQL更改(UPDATE、REPLACE、DELETE)
|
||||
*
|
||||
* @param sql SQL语句内容
|
||||
* @param params SQL语句中 ? 的对应参数
|
||||
* @return 更新的行数
|
||||
* @see PreparedSQLUpdateAction
|
||||
*/
|
||||
@Nullable Integer executeSQL(String sql, Object[] params);
|
||||
|
||||
/**
|
||||
* 执行多条不需要返回结果的SQL更改(UPDATE、REPLACE、DELETE)
|
||||
*
|
||||
* @param sql SQL语句内容
|
||||
* @param paramsBatch SQL语句中对应?的参数组
|
||||
* @return 对应参数返回的行数
|
||||
* @see PreparedSQLUpdateBatchAction
|
||||
*/
|
||||
@Nullable List<Integer> executeSQLBatch(String sql, Iterable<Object[]> paramsBatch);
|
||||
|
||||
|
||||
/**
|
||||
* 执行多条不需要返回结果的SQL。
|
||||
* 该方法使用 Statement 实现,请注意SQL注入风险!
|
||||
*
|
||||
* @param sql SQL语句内容
|
||||
* @param moreSQL 更多SQL语句内容
|
||||
* @return 对应参数返回的行数
|
||||
* @see SQLUpdateBatchAction
|
||||
*/
|
||||
@Nullable List<Integer> executeSQLBatch(@NotNull String sql, String... moreSQL);
|
||||
|
||||
/**
|
||||
* 执行多条不需要返回结果的SQL。
|
||||
*
|
||||
* @param sqlBatch SQL语句内容
|
||||
* @return 对应参数返回的行数
|
||||
*/
|
||||
@Nullable List<Integer> executeSQLBatch(@NotNull Iterable<String> sqlBatch);
|
||||
|
||||
/**
|
||||
* 获取并操作 {@link DatabaseMetaData} 以得到需要的数据库消息。
|
||||
*
|
||||
* @param reader 操作与读取的方法
|
||||
* @param <R> 最终结果的返回类型
|
||||
* @return 最终结果,通过 {@link CompletableFuture#get()} 可阻塞并等待结果返回。
|
||||
*/
|
||||
default <R> CompletableFuture<R> fetchMetadata(@NotNull SQLFunction<DatabaseMetaData, R> reader) {
|
||||
return fetchMetadata((meta, conn) -> reader.apply(meta));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取并操作 {@link DatabaseMetaData} 提供的指定 {@link ResultSet} 以得到需要的数据库消息。
|
||||
* <br> 该方法会自动关闭 {@link ResultSet} 。
|
||||
*
|
||||
* @param supplier 操作 {@link DatabaseMetaData} 以提供信息所在的 {@link ResultSet}
|
||||
* @param reader 读取 {@link ResultSet} 中指定信息的方法
|
||||
* @param <R> 最终结果的返回类型
|
||||
* @return 最终结果,通过 {@link CompletableFuture#get()} 可阻塞并等待结果返回。
|
||||
* @throws NullPointerException 当 supplier 提供的 {@link ResultSet} 为NULL时抛出
|
||||
*/
|
||||
default <R> CompletableFuture<R> fetchMetadata(@NotNull SQLFunction<DatabaseMetaData, ResultSet> supplier,
|
||||
@NotNull SQLFunction<@NotNull ResultSet, R> reader) {
|
||||
return fetchMetadata((meta, conn) -> supplier.apply(meta), reader);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取并操作 {@link DatabaseMetaData} 以得到需要的数据库消息。
|
||||
*
|
||||
* @param reader 操作与读取的方法
|
||||
* @param <R> 最终结果的返回类型
|
||||
* @return 最终结果,通过 {@link CompletableFuture#get()} 可阻塞并等待结果返回。
|
||||
*/
|
||||
<R> CompletableFuture<R> fetchMetadata(@NotNull SQLBiFunction<DatabaseMetaData, Connection, R> reader);
|
||||
|
||||
/**
|
||||
* 获取并操作 {@link DatabaseMetaData} 提供的指定 {@link ResultSet} 以得到需要的数据库消息。
|
||||
* <br> 该方法会自动关闭 {@link ResultSet} 。
|
||||
*
|
||||
* @param supplier 操作 {@link DatabaseMetaData} 以提供信息所在的 {@link ResultSet}
|
||||
* @param reader 读取 {@link ResultSet} 中指定信息的方法
|
||||
* @param <R> 最终结果的返回类型
|
||||
* @return 最终结果,通过 {@link CompletableFuture#get()} 可阻塞并等待结果返回。
|
||||
* @throws NullPointerException 当 supplier 提供的 {@link ResultSet} 为NULL时抛出
|
||||
*/
|
||||
<R> CompletableFuture<R> fetchMetadata(@NotNull SQLBiFunction<DatabaseMetaData, Connection, ResultSet> supplier,
|
||||
@NotNull SQLFunction<@NotNull ResultSet, R> reader);
|
||||
|
||||
/**
|
||||
* 在库中创建一个表。
|
||||
*
|
||||
* @param tableName 表名
|
||||
* @return {@link TableCreateBuilder}
|
||||
*/
|
||||
TableCreateBuilder createTable(@NotNull String tableName);
|
||||
|
||||
/**
|
||||
* 对库中的某个表执行更改。
|
||||
*
|
||||
* @param tableName 表名
|
||||
* @return {@link TableAlterBuilder}
|
||||
*/
|
||||
TableAlterBuilder alterTable(@NotNull String tableName);
|
||||
|
||||
/**
|
||||
* 快速获取表的部分元数据。
|
||||
* <br> 当需要获取其他元数据时,请使用 {@link #fetchMetadata(SQLFunction, SQLFunction)} 方法。
|
||||
*
|
||||
* @param tablePattern 表名通配符
|
||||
* @return {@link TableMetadataBuilder}
|
||||
*/
|
||||
TableMetadataBuilder fetchTableMetadata(@NotNull String tablePattern);
|
||||
|
||||
/**
|
||||
* 新建一个查询。
|
||||
*
|
||||
* @return {@link QueryBuilder}
|
||||
*/
|
||||
QueryBuilder createQuery();
|
||||
|
||||
/**
|
||||
* 创建一条插入操作。
|
||||
*
|
||||
* @param tableName 目标表名
|
||||
* @return {@link InsertBuilder}
|
||||
*/
|
||||
InsertBuilder<PreparedSQLUpdateAction<Integer>> createInsert(@NotNull String tableName);
|
||||
|
||||
/**
|
||||
* 创建支持多组数据的插入操作。
|
||||
*
|
||||
* @param tableName 目标表名
|
||||
* @return {@link InsertBuilder}
|
||||
*/
|
||||
InsertBuilder<PreparedSQLUpdateBatchAction<Integer>> createInsertBatch(@NotNull String tableName);
|
||||
|
||||
/**
|
||||
* 创建一条替换操作。
|
||||
*
|
||||
* @param tableName 目标表名
|
||||
* @return {@link ReplaceBuilder}
|
||||
*/
|
||||
ReplaceBuilder<PreparedSQLUpdateAction<Integer>> createReplace(@NotNull String tableName);
|
||||
|
||||
/**
|
||||
* 创建支持多组数据的替换操作。
|
||||
*
|
||||
* @param tableName 目标表名
|
||||
* @return {@link ReplaceBuilder}
|
||||
*/
|
||||
ReplaceBuilder<PreparedSQLUpdateBatchAction<Integer>> createReplaceBatch(@NotNull String tableName);
|
||||
|
||||
/**
|
||||
* 创建更新操作。
|
||||
*
|
||||
* @param tableName 目标表名
|
||||
* @return {@link UpdateBuilder}
|
||||
*/
|
||||
UpdateBuilder createUpdate(@NotNull String tableName);
|
||||
|
||||
/**
|
||||
* 创建删除操作。
|
||||
*
|
||||
* @param tableName 目标表名
|
||||
* @return {@link DeleteBuilder}
|
||||
*/
|
||||
DeleteBuilder createDelete(@NotNull String tableName);
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package com.io.yutian.elementoriginlib.sql.api;
|
||||
|
||||
import com.io.yutian.elementoriginlib.sql.api.action.query.PreparedQueryAction;
|
||||
import com.io.yutian.elementoriginlib.sql.api.action.query.QueryAction;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* SQLQuery 是一个查询中间接口,用于查询操作的封装。
|
||||
*
|
||||
* @author CarmJos
|
||||
*/
|
||||
public interface SQLQuery extends AutoCloseable {
|
||||
|
||||
/**
|
||||
* 获取该查询创建的时间
|
||||
* <br>注意,此处获得的时间非时间戳毫秒数,仅用于计算耗时。
|
||||
*
|
||||
* @return 创建时间
|
||||
*/
|
||||
default long getExecuteTime() {
|
||||
return getExecuteTime(TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取该查询创建的时间
|
||||
* <br>注意,此处获得的时间非时间戳毫秒数,仅用于计算耗时。
|
||||
*
|
||||
* @param timeUnit 时间单位
|
||||
* @return 创建时间
|
||||
*/
|
||||
long getExecuteTime(TimeUnit timeUnit);
|
||||
|
||||
/**
|
||||
* 得到承载该SQLQuery的对应{@link SQLManager}
|
||||
*
|
||||
* @return {@link SQLManager}
|
||||
*/
|
||||
SQLManager getManager();
|
||||
|
||||
/**
|
||||
* 得到承载该SQLQuery的对应{@link QueryAction}
|
||||
*
|
||||
* @return {@link QueryAction} 或 {@link PreparedQueryAction}
|
||||
*/
|
||||
QueryAction getAction();
|
||||
|
||||
ResultSet getResultSet();
|
||||
|
||||
default boolean containsResult(String columnName) throws SQLException {
|
||||
return getResultSet() != null && getResultSet().getObject(columnName) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到设定的SQL语句
|
||||
*
|
||||
* @return SQL语句
|
||||
*/
|
||||
String getSQLContent();
|
||||
|
||||
/**
|
||||
* 关闭所有内容
|
||||
*/
|
||||
@Override
|
||||
void close();
|
||||
|
||||
Statement getStatement();
|
||||
|
||||
Connection getConnection();
|
||||
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
package com.io.yutian.elementoriginlib.sql.api;
|
||||
|
||||
import com.io.yutian.elementoriginlib.sql.api.action.PreparedSQLUpdateAction;
|
||||
import com.io.yutian.elementoriginlib.sql.api.action.PreparedSQLUpdateBatchAction;
|
||||
import com.io.yutian.elementoriginlib.sql.api.builder.*;
|
||||
import com.io.yutian.elementoriginlib.sql.api.function.SQLHandler;
|
||||
import com.io.yutian.elementoriginlib.sql.api.table.NamedSQLTable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* SQLTable 基于 {@link TableCreateBuilder} 构建表,用于快速创建与该表相关的操作。
|
||||
* <ul>
|
||||
* <li>1. 调用 {@link NamedSQLTable#of(String, String[])} 方法创建一个 SQLTable 对象;</li>
|
||||
* <li>2. 在应用初始化阶段调用 {@link NamedSQLTable#create(SQLManager)} 方法初始化 SQLTable 对象;</li>
|
||||
* <li>3. 获取已创建的{@link NamedSQLTable} 实例,直接调用对应方法进行关于表的相关操作。</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author CarmJos
|
||||
* @since 0.3.10
|
||||
*/
|
||||
public interface SQLTable {
|
||||
|
||||
static @NotNull NamedSQLTable of(@NotNull String tableName, @Nullable SQLHandler<TableCreateBuilder> table) {
|
||||
return new NamedSQLTable(tableName) {
|
||||
@Override
|
||||
public boolean create(@NotNull SQLManager sqlManager, String tablePrefix) throws SQLException {
|
||||
if (this.manager == null) this.manager = sqlManager;
|
||||
this.tablePrefix = tablePrefix;
|
||||
|
||||
TableCreateBuilder tableBuilder = sqlManager.createTable(getTableName());
|
||||
if (table != null) table.accept(tableBuilder);
|
||||
return tableBuilder.build().executeFunction(l -> l > 0, false);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static @NotNull NamedSQLTable of(@NotNull String tableName, @NotNull String[] columns) {
|
||||
return of(tableName, columns, null);
|
||||
}
|
||||
|
||||
static @NotNull NamedSQLTable of(@NotNull String tableName,
|
||||
@NotNull String[] columns, @Nullable String tableSettings) {
|
||||
return of(tableName, builder -> {
|
||||
builder.setColumns(columns);
|
||||
if (tableSettings != null) builder.setTableSettings(tableSettings);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 以指定的 {@link SQLManager} 实例初始化并创建该表
|
||||
*
|
||||
* @param sqlManager {@link SQLManager} 实例
|
||||
* @return 是否新创建了本表 (若已创建或创建失败则返回false)
|
||||
* @throws SQLException 当数据库返回异常时抛出
|
||||
*/
|
||||
boolean create(SQLManager sqlManager) throws SQLException;
|
||||
|
||||
/**
|
||||
* 得到 {@link #create(SQLManager)} 用于初始化本实例的 {@link SQLManager} 实例
|
||||
*
|
||||
* @return {@link SQLManager} 实例
|
||||
*/
|
||||
@Nullable SQLManager getSQLManager();
|
||||
|
||||
/**
|
||||
* 得到本表表名,不得为空。
|
||||
*
|
||||
* @return 本表表名
|
||||
*/
|
||||
@NotNull String getTableName();
|
||||
|
||||
default @NotNull TableQueryBuilder createQuery() {
|
||||
return Optional.ofNullable(getSQLManager()).map(this::createQuery)
|
||||
.orElseThrow(() -> new NullPointerException("This table doesn't have a SQLManger."));
|
||||
}
|
||||
|
||||
default @NotNull TableQueryBuilder createQuery(@NotNull SQLManager sqlManager) {
|
||||
return sqlManager.createQuery().inTable(getTableName());
|
||||
}
|
||||
|
||||
default @NotNull DeleteBuilder createDelete() {
|
||||
return Optional.ofNullable(getSQLManager()).map(this::createDelete)
|
||||
.orElseThrow(() -> new NullPointerException("This table doesn't have a SQLManger."));
|
||||
}
|
||||
|
||||
default @NotNull DeleteBuilder createDelete(@NotNull SQLManager sqlManager) {
|
||||
return sqlManager.createDelete(getTableName());
|
||||
}
|
||||
|
||||
default @NotNull UpdateBuilder createUpdate() {
|
||||
return Optional.ofNullable(getSQLManager()).map(this::createUpdate)
|
||||
.orElseThrow(() -> new NullPointerException("This table doesn't have a SQLManger."));
|
||||
}
|
||||
|
||||
default @NotNull UpdateBuilder createUpdate(@NotNull SQLManager sqlManager) {
|
||||
return sqlManager.createUpdate(getTableName());
|
||||
}
|
||||
|
||||
default @NotNull InsertBuilder<PreparedSQLUpdateAction<Integer>> createInsert() {
|
||||
return Optional.ofNullable(getSQLManager()).map(this::createInsert)
|
||||
.orElseThrow(() -> new NullPointerException("This table doesn't have a SQLManger."));
|
||||
}
|
||||
|
||||
default @NotNull InsertBuilder<PreparedSQLUpdateAction<Integer>> createInsert(@NotNull SQLManager sqlManager) {
|
||||
return sqlManager.createInsert(getTableName());
|
||||
}
|
||||
|
||||
default @NotNull InsertBuilder<PreparedSQLUpdateBatchAction<Integer>> createInsertBatch() {
|
||||
return Optional.ofNullable(getSQLManager()).map(this::createInsertBatch)
|
||||
.orElseThrow(() -> new NullPointerException("This table doesn't have a SQLManger."));
|
||||
}
|
||||
|
||||
default @NotNull InsertBuilder<PreparedSQLUpdateBatchAction<Integer>> createInsertBatch(@NotNull SQLManager sqlManager) {
|
||||
return sqlManager.createInsertBatch(getTableName());
|
||||
}
|
||||
|
||||
default @NotNull ReplaceBuilder<PreparedSQLUpdateAction<Integer>> createReplace() {
|
||||
return Optional.ofNullable(getSQLManager()).map(this::createReplace)
|
||||
.orElseThrow(() -> new NullPointerException("This table doesn't have a SQLManger."));
|
||||
|
||||
}
|
||||
|
||||
default @NotNull ReplaceBuilder<PreparedSQLUpdateAction<Integer>> createReplace(@NotNull SQLManager sqlManager) {
|
||||
return sqlManager.createReplace(getTableName());
|
||||
}
|
||||
|
||||
default @NotNull ReplaceBuilder<PreparedSQLUpdateBatchAction<Integer>> createReplaceBatch() {
|
||||
return Optional.ofNullable(getSQLManager()).map(this::createReplaceBatch)
|
||||
.orElseThrow(() -> new NullPointerException("This table doesn't have a SQLManger."));
|
||||
}
|
||||
|
||||
default @NotNull ReplaceBuilder<PreparedSQLUpdateBatchAction<Integer>> createReplaceBatch(@NotNull SQLManager sqlManager) {
|
||||
return sqlManager.createReplaceBatch(getTableName());
|
||||
}
|
||||
|
||||
default @NotNull TableAlterBuilder alter() {
|
||||
return Optional.ofNullable(getSQLManager()).map(this::alter)
|
||||
.orElseThrow(() -> new NullPointerException("This table doesn't have a SQLManger."));
|
||||
}
|
||||
|
||||
default @NotNull TableAlterBuilder alter(@NotNull SQLManager sqlManager) {
|
||||
return sqlManager.alterTable(getTableName());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.io.yutian.elementoriginlib.sql.api.action;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface PreparedSQLUpdateAction<T extends Number> extends SQLUpdateAction<T> {
|
||||
|
||||
/**
|
||||
* 设定SQL语句中所有 ? 对应的参数
|
||||
*
|
||||
* @param params 参数内容
|
||||
* @return {@link PreparedSQLUpdateAction}
|
||||
*/
|
||||
PreparedSQLUpdateAction<T> setParams(Object... params);
|
||||
|
||||
/**
|
||||
* 设定SQL语句中所有 ? 对应的参数
|
||||
*
|
||||
* @param params 参数内容
|
||||
* @return {@link PreparedSQLUpdateAction}
|
||||
* @since 0.4.0
|
||||
*/
|
||||
PreparedSQLUpdateAction<T> setParams(@Nullable Iterable<Object> params);
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package com.io.yutian.elementoriginlib.sql.api.action;
|
||||
|
||||
import com.io.yutian.elementoriginlib.sql.api.SQLAction;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface PreparedSQLUpdateBatchAction<T extends Number> extends SQLAction<List<T>> {
|
||||
|
||||
/**
|
||||
* 设定多组SQL语句中所有 ? 对应的参数
|
||||
*
|
||||
* @param allParams 所有参数内容
|
||||
* @return {@link PreparedSQLUpdateBatchAction}
|
||||
*/
|
||||
PreparedSQLUpdateBatchAction<T> setAllParams(Iterable<Object[]> allParams);
|
||||
|
||||
/**
|
||||
* 添加一组SQL语句中所有 ? 对应的参数
|
||||
*
|
||||
* @param params 参数内容
|
||||
* @return {@link PreparedSQLUpdateBatchAction}
|
||||
*/
|
||||
PreparedSQLUpdateBatchAction<T> addParamsBatch(Object... params);
|
||||
|
||||
/**
|
||||
* 设定该操作返回自增键序列。
|
||||
*
|
||||
* @return {@link SQLUpdateAction}
|
||||
*/
|
||||
PreparedSQLUpdateBatchAction<T> returnGeneratedKeys();
|
||||
|
||||
/**
|
||||
* 设定该操作返回自增键序列。
|
||||
*
|
||||
* @param keyTypeClass 自增序列的数字类型
|
||||
* @param <N> 自增键序列类型 {@link Number}
|
||||
* @return {@link SQLUpdateAction}
|
||||
* @since 0.4.0
|
||||
*/
|
||||
<N extends Number> PreparedSQLUpdateBatchAction<N> returnGeneratedKeys(Class<N> keyTypeClass);
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.io.yutian.elementoriginlib.sql.api.action;
|
||||
|
||||
import com.io.yutian.elementoriginlib.sql.api.SQLAction;
|
||||
|
||||
public interface SQLUpdateAction<T extends Number> extends SQLAction<T> {
|
||||
|
||||
|
||||
/**
|
||||
* 设定该操作返回自增键序列。
|
||||
*
|
||||
* @return {@link SQLUpdateAction}
|
||||
*/
|
||||
SQLUpdateAction<T> returnGeneratedKey();
|
||||
|
||||
/**
|
||||
* 设定该操作返回自增键序列。
|
||||
*
|
||||
* @param keyTypeClass 自增序列的数字类型
|
||||
* @param <N> 自增键序列类型 {@link Number}
|
||||
* @return {@link SQLUpdateAction}
|
||||
* @since 0.4.0
|
||||
*/
|
||||
<N extends Number> SQLUpdateAction<N> returnGeneratedKey(Class<N> keyTypeClass);
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.io.yutian.elementoriginlib.sql.api.action;
|
||||
|
||||
import com.io.yutian.elementoriginlib.sql.api.SQLAction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public interface SQLUpdateBatchAction extends SQLAction<List<Integer>> {
|
||||
|
||||
/**
|
||||
* 添加一条批量执行的SQL语句
|
||||
*
|
||||
* @param sql SQL语句
|
||||
* @return {@link SQLUpdateBatchAction}
|
||||
*/
|
||||
SQLUpdateBatchAction addBatch(@NotNull String sql);
|
||||
|
||||
@Override
|
||||
default @NotNull String getSQLContent() {
|
||||
return getSQLContents().get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull List<String> getSQLContents();
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.io.yutian.elementoriginlib.sql.api.action.query;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public interface PreparedQueryAction extends QueryAction {
|
||||
|
||||
/**
|
||||
* 设定SQL语句中所有 ? 对应的参数
|
||||
*
|
||||
* @param params 参数内容
|
||||
* @return {@link PreparedQueryAction}
|
||||
*/
|
||||
PreparedQueryAction setParams(@Nullable Object... params);
|
||||
|
||||
/**
|
||||
* 设定SQL语句中所有 ? 对应的参数
|
||||
*
|
||||
* @param params 参数内容
|
||||
* @return {@link PreparedQueryAction}
|
||||
*/
|
||||
PreparedQueryAction setParams(@Nullable Iterable<Object> params);
|
||||
|
||||
/**
|
||||
* 直接对 {@link PreparedStatement} 进行处理
|
||||
*
|
||||
* @param statement {@link Consumer} 处理操作
|
||||
* 若为空则不进行处理
|
||||
* @return {@link PreparedQueryAction}
|
||||
*/
|
||||
PreparedQueryAction handleStatement(@Nullable Consumer<PreparedStatement> statement);
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package com.io.yutian.elementoriginlib.sql.api.action.query;
|
||||
|
||||
import com.io.yutian.elementoriginlib.sql.api.SQLAction;
|
||||
import com.io.yutian.elementoriginlib.sql.api.SQLQuery;
|
||||
import com.io.yutian.elementoriginlib.sql.api.function.SQLExceptionHandler;
|
||||
import com.io.yutian.elementoriginlib.sql.api.function.SQLFunction;
|
||||
import com.io.yutian.elementoriginlib.sql.api.function.SQLHandler;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* SQLQueryAction 是用于承载SQL查询语句并进行处理、返回并自动关闭连接的基本类。
|
||||
*
|
||||
* <ul>
|
||||
* <li>同步执行 {@link #execute()}, {@link #execute(SQLFunction, SQLExceptionHandler)}
|
||||
* <br>同步执行方法中有会抛出异常的方法与不抛出异常的方法,
|
||||
* <br>若选择不抛出异常,则返回值可能为空,需要特殊处理。</li>
|
||||
*
|
||||
* <li>异步执行 {@link #executeAsync(SQLHandler, SQLExceptionHandler)}
|
||||
* <br>异步执行时将提供成功与异常两种处理方式
|
||||
* <br>可自行选择是否对数据或异常进行处理
|
||||
* <br>默认的异常处理器为 {@link #defaultExceptionHandler()}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <b>注意: 无论是否异步,都不需要自行关闭ResultSet,本API已自动关闭</b>
|
||||
*
|
||||
* @author CarmJos
|
||||
* @since 0.2.6
|
||||
*/
|
||||
public interface QueryAction extends SQLAction<SQLQuery> {
|
||||
|
||||
@Override
|
||||
@Contract("_,!null -> !null")
|
||||
default <R> @Nullable R executeFunction(@NotNull SQLFunction<@NotNull SQLQuery, R> function,
|
||||
@Nullable R defaultResult) throws SQLException {
|
||||
try (SQLQuery value = execute()) {
|
||||
R result = function.apply(value);
|
||||
return result == null ? defaultResult : result;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package com.io.yutian.elementoriginlib.sql.api.builder;
|
||||
|
||||
import com.io.yutian.elementoriginlib.sql.api.SQLAction;
|
||||
import com.io.yutian.elementoriginlib.sql.api.SQLBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
public interface ConditionalBuilder<B extends ConditionalBuilder<B, T>, T extends SQLAction<?>> extends SQLBuilder {
|
||||
|
||||
/**
|
||||
* 将现有条件构建完整的SQL语句用于执行。
|
||||
*
|
||||
* @return {@link SQLAction}
|
||||
*/
|
||||
T build();
|
||||
|
||||
/**
|
||||
* 设定限定的条目数
|
||||
*
|
||||
* @param limit 条数限制
|
||||
* @return {@link B}
|
||||
*/
|
||||
B setLimit(int limit);
|
||||
|
||||
/**
|
||||
* 直接设定条件的源文本,不需要以WHERE开头。
|
||||
* <br>如 {@code id = 1 AND name = 'test' OR name = 'test2'} 。
|
||||
*
|
||||
* @param condition 条件文本,不需要以WHERE开头。
|
||||
* @return {@link B}
|
||||
*/
|
||||
B setConditions(@Nullable String condition);
|
||||
|
||||
/**
|
||||
* 直接设定每个条件的文本与其对应数值,将以AND链接,且不需要以WHERE开头。
|
||||
* <br>条件如 {@code id = ? },问号将被以对应的数值填充。。
|
||||
*
|
||||
* @param conditionSQLs 条件内容,将以AND链接,且不需要以WHERE开头。
|
||||
* @return {@link B}
|
||||
*/
|
||||
B setConditions(LinkedHashMap<@NotNull String, @Nullable Object> conditionSQLs);
|
||||
|
||||
B addCondition(@Nullable String condition);
|
||||
|
||||
B addCondition(@NotNull String columnName, @NotNull String operator, @Nullable Object queryValue);
|
||||
|
||||
B addCondition(@NotNull String columnName, @Nullable Object queryValue);
|
||||
|
||||
B addCondition(@NotNull String[] columnNames, @Nullable Object[] queryValues);
|
||||
|
||||
B addNotNullCondition(@NotNull String columnName);
|
||||
|
||||
/**
|
||||
* 添加时间的限定条件。 若设定了开始时间,则限定条件为 {@code endMillis >= startMillis};
|
||||
*
|
||||
* @param columnName 判断的行
|
||||
* @param startMillis 开始时间戳,若{@code <0}则不作限定
|
||||
* @param endMillis 结束时间戳,若{@code <0}则不作限定
|
||||
* @return {@link B}
|
||||
*/
|
||||
default B addTimeCondition(@NotNull String columnName, long startMillis, long endMillis) {
|
||||
return addTimeCondition(columnName,
|
||||
startMillis > 0 ? new Date(startMillis) : null,
|
||||
endMillis > 0 ? new Date(endMillis) : null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加时间的限定条件。 若设定了开始时间,则限定条件为 {@code endDate >= startTime};
|
||||
*
|
||||
* @param columnName 判断的行
|
||||
* @param startDate 开始时间,若为null则不作限定
|
||||
* @param endDate 结束时间,若为null则不作限定
|
||||
* @return {@link B}
|
||||
*/
|
||||
B addTimeCondition(@NotNull String columnName, @Nullable Date startDate, @Nullable Date endDate);
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.io.yutian.elementoriginlib.sql.api.builder;
|
||||
|
||||
import com.io.yutian.elementoriginlib.sql.api.SQLAction;
|
||||
|
||||
public interface DeleteBuilder extends ConditionalBuilder<DeleteBuilder, SQLAction<Integer>> {
|
||||
|
||||
String getTableName();
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.io.yutian.elementoriginlib.sql.api.builder;
|
||||
|
||||
import com.io.yutian.elementoriginlib.sql.api.SQLAction;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public interface InsertBuilder<T extends SQLAction<?>> {
|
||||
|
||||
String getTableName();
|
||||
|
||||
boolean isIgnore();
|
||||
|
||||
InsertBuilder<T> setIgnore(boolean ignore);
|
||||
|
||||
T setColumnNames(List<String> columnNames);
|
||||
|
||||
default T setColumnNames(String... columnNames) {
|
||||
return setColumnNames(columnNames == null ? null : Arrays.asList(columnNames));
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package com.io.yutian.elementoriginlib.sql.api.builder;
|
||||
|
||||
import com.io.yutian.elementoriginlib.sql.api.SQLBuilder;
|
||||
import com.io.yutian.elementoriginlib.sql.api.action.query.PreparedQueryAction;
|
||||
import com.io.yutian.elementoriginlib.sql.api.action.query.QueryAction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface QueryBuilder extends SQLBuilder {
|
||||
|
||||
/**
|
||||
* 通过一条 SQL语句创建查询。
|
||||
* 该方法使用 Statement 实现,请注意SQL注入风险!
|
||||
*
|
||||
* @param sql SQL语句
|
||||
* @return {@link QueryAction}
|
||||
* @deprecated 存在SQL注入风险,建议使用 {@link QueryBuilder#withPreparedSQL(String)}
|
||||
*/
|
||||
@Deprecated
|
||||
QueryAction withSQL(@NotNull String sql);
|
||||
|
||||
/**
|
||||
* 通过一条 SQL语句创建预查询
|
||||
*
|
||||
* @param sql SQL语句
|
||||
* @return {@link PreparedQueryAction}
|
||||
*/
|
||||
PreparedQueryAction withPreparedSQL(@NotNull String sql);
|
||||
|
||||
/**
|
||||
* 创建表查询
|
||||
*
|
||||
* @param tableName 表名
|
||||
* @return {@link TableQueryBuilder}
|
||||
*/
|
||||
TableQueryBuilder inTable(@NotNull String tableName);
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.io.yutian.elementoriginlib.sql.api.builder;
|
||||
|
||||
import com.io.yutian.elementoriginlib.sql.api.SQLAction;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* REPLACE 语句用于将一组值更新进数据表中。
|
||||
* <br> 执行后,将通过表中键判断该数据是否存在,若存在则用新数据替换原来的值,若不存在则会插入该数据。
|
||||
* <br> 在使用REPLACE时,表与所给行列数据中必须包含唯一索引(或主键),且索引不得为空值,否则将等同于插入语句。
|
||||
*
|
||||
* @param <T> 最终构建出的 {@link SQLAction} 类型
|
||||
*/
|
||||
public interface ReplaceBuilder<T extends SQLAction<?>> {
|
||||
|
||||
String getTableName();
|
||||
|
||||
T setColumnNames(List<String> columnNames);
|
||||
|
||||
default T setColumnNames(String... columnNames) {
|
||||
return setColumnNames(columnNames == null ? null : Arrays.asList(columnNames));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
package com.io.yutian.elementoriginlib.sql.api.builder;
|
||||
|
||||
import com.io.yutian.elementoriginlib.sql.api.SQLAction;
|
||||
import com.io.yutian.elementoriginlib.sql.api.SQLBuilder;
|
||||
import com.io.yutian.elementoriginlib.sql.api.action.SQLUpdateAction;
|
||||
import com.io.yutian.elementoriginlib.sql.api.enums.IndexType;
|
||||
import com.io.yutian.elementoriginlib.sql.api.enums.NumberType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface TableAlterBuilder extends SQLBuilder {
|
||||
|
||||
SQLAction<Integer> renameTo(@NotNull String newTableName);
|
||||
|
||||
SQLAction<Integer> changeComment(@NotNull String newTableComment);
|
||||
|
||||
SQLAction<Integer> setAutoIncrementIndex(int index);
|
||||
|
||||
SQLAction<Integer> addIndex(@NotNull IndexType indexType, @Nullable String indexName,
|
||||
@NotNull String columnName, @NotNull String... moreColumns);
|
||||
|
||||
/**
|
||||
* 为该表移除一个索引
|
||||
*
|
||||
* @param indexName 索引名
|
||||
* @return {@link SQLUpdateAction}
|
||||
*/
|
||||
SQLAction<Integer> dropIndex(@NotNull String indexName);
|
||||
|
||||
/**
|
||||
* 为该表移除一个外键
|
||||
*
|
||||
* @param keySymbol 外键名
|
||||
* @return {@link SQLUpdateAction}
|
||||
*/
|
||||
SQLAction<Integer> dropForeignKey(@NotNull String keySymbol);
|
||||
|
||||
/**
|
||||
* 为该表移除主键(须添加新主键)
|
||||
*
|
||||
* @return {@link SQLUpdateAction}
|
||||
*/
|
||||
SQLAction<Integer> dropPrimaryKey();
|
||||
|
||||
/**
|
||||
* 为表添加一列
|
||||
*
|
||||
* @param columnName 列名
|
||||
* @param settings 列的相关设定
|
||||
* @return {@link SQLUpdateAction}
|
||||
*/
|
||||
default SQLAction<Integer> addColumn(@NotNull String columnName, @NotNull String settings) {
|
||||
return addColumn(columnName, settings, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 为表添加一列
|
||||
*
|
||||
* @param columnName 列名
|
||||
* @param settings 列的相关设定
|
||||
* @param afterColumn 该列增添到哪个列的后面,
|
||||
* <p> 该参数若省缺则放于最后一行
|
||||
* <p> 若为 "" 则置于首行。
|
||||
* @return {@link SQLUpdateAction}
|
||||
*/
|
||||
SQLAction<Integer> addColumn(@NotNull String columnName, @NotNull String settings, @Nullable String afterColumn);
|
||||
|
||||
SQLAction<Integer> renameColumn(@NotNull String columnName, @NotNull String newName);
|
||||
|
||||
SQLAction<Integer> modifyColumn(@NotNull String columnName, @NotNull String settings);
|
||||
|
||||
default SQLAction<Integer> modifyColumn(@NotNull String columnName, @NotNull String columnSettings, @NotNull String afterColumn) {
|
||||
return modifyColumn(columnName, columnSettings + " AFTER `" + afterColumn + "`");
|
||||
}
|
||||
|
||||
SQLAction<Integer> removeColumn(@NotNull String columnName);
|
||||
|
||||
SQLAction<Integer> setColumnDefault(@NotNull String columnName, @NotNull String defaultValue);
|
||||
|
||||
SQLAction<Integer> removeColumnDefault(@NotNull String columnName);
|
||||
|
||||
/**
|
||||
* 为该表添加一个自增列
|
||||
* <p> 自增列强制要求为数字类型,非空,且为UNIQUE。
|
||||
* <p> 注意:一个表只允许有一个自增列!
|
||||
*
|
||||
* @param columnName 列名
|
||||
* @param numberType 数字类型,若省缺则为 {@link NumberType#INT}
|
||||
* @param primary 是否为主键,若否则只为唯一键
|
||||
* @param unsigned 是否采用 UNSIGNED (即无负数,可以增加自增键的最高数,建议为true)
|
||||
* @return {@link TableCreateBuilder}
|
||||
*/
|
||||
default SQLAction<Integer> addAutoIncrementColumn(@NotNull String columnName, @Nullable NumberType numberType,
|
||||
boolean primary, boolean unsigned) {
|
||||
return addColumn(columnName,
|
||||
(numberType == null ? NumberType.INT : numberType).name()
|
||||
+ (unsigned ? " UNSIGNED " : " ")
|
||||
+ "NOT NULL AUTO_INCREMENT " + (primary ? "PRIMARY KEY" : "UNIQUE KEY"),
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 为该表添加一个自增列
|
||||
* <br> 自增列强制要求为数字类型,非空,且为UNIQUE。
|
||||
* <p> 注意:一个表只允许有一个自增列!
|
||||
*
|
||||
* @param columnName 列名
|
||||
* @param numberType 数字类型,若省缺则为 {@link NumberType#INT}
|
||||
* @return {@link TableAlterBuilder}
|
||||
*/
|
||||
default SQLAction<Integer> addAutoIncrementColumn(@NotNull String columnName, @NotNull NumberType numberType) {
|
||||
return addAutoIncrementColumn(columnName, numberType, false, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 为该表添加一个自增列
|
||||
* <br> 自增列强制要求为数字类型,非空,且为UNIQUE。
|
||||
* <p> 注意:一个表只允许有一个自增列!
|
||||
*
|
||||
* @param columnName 列名
|
||||
* @return {@link TableAlterBuilder}
|
||||
*/
|
||||
default SQLAction<Integer> addAutoIncrementColumn(@NotNull String columnName) {
|
||||
return addAutoIncrementColumn(columnName, NumberType.INT);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,256 @@
|
|||
package com.io.yutian.elementoriginlib.sql.api.builder;
|
||||
|
||||
import com.io.yutian.elementoriginlib.sql.api.SQLBuilder;
|
||||
import com.io.yutian.elementoriginlib.sql.api.action.SQLUpdateAction;
|
||||
import com.io.yutian.elementoriginlib.sql.api.enums.ForeignKeyRule;
|
||||
import com.io.yutian.elementoriginlib.sql.api.enums.IndexType;
|
||||
import com.io.yutian.elementoriginlib.sql.api.enums.NumberType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.io.yutian.elementoriginlib.sql.api.SQLBuilder.withBackQuote;
|
||||
import static com.io.yutian.elementoriginlib.sql.api.SQLBuilder.withQuote;
|
||||
|
||||
|
||||
public interface TableCreateBuilder extends SQLBuilder {
|
||||
|
||||
/**
|
||||
* 将现有条件构建完整的SQL语句用于执行。
|
||||
*
|
||||
* @return {@link SQLUpdateAction}
|
||||
*/
|
||||
SQLUpdateAction<Integer> build();
|
||||
|
||||
@NotNull String getTableName();
|
||||
|
||||
/**
|
||||
* 得到表的设定。
|
||||
* <p> 若未使用 {@link #setTableSettings(String)} 方法则会采用 {@link #defaultTablesSettings()} 。
|
||||
*
|
||||
* @return TableSettings
|
||||
*/
|
||||
@NotNull String getTableSettings();
|
||||
|
||||
TableCreateBuilder setTableSettings(@NotNull String settings);
|
||||
|
||||
/**
|
||||
* 设定表的标注,一般用于解释该表的作用。
|
||||
*
|
||||
* @param comment 表标注
|
||||
* @return {@link TableCreateBuilder}
|
||||
*/
|
||||
TableCreateBuilder setTableComment(@Nullable String comment);
|
||||
|
||||
/**
|
||||
* 直接设定表的所有列信息
|
||||
*
|
||||
* @param columns 列的相关信息 (包括列设定)
|
||||
* @return {@link TableCreateBuilder}
|
||||
*/
|
||||
TableCreateBuilder setColumns(@NotNull String... columns);
|
||||
|
||||
/**
|
||||
* 为该表添加一个列
|
||||
*
|
||||
* @param column 列的相关信息
|
||||
* <br>如 `uuid` VARCHAR(36) NOT NULL UNIQUE KEY
|
||||
* @return {@link TableCreateBuilder}
|
||||
*/
|
||||
TableCreateBuilder addColumn(@NotNull String column);
|
||||
|
||||
/**
|
||||
* 为该表添加一个列
|
||||
*
|
||||
* @param columnName 列名
|
||||
* @param settings 列的设定
|
||||
* <br>如 VARCHAR(36) NOT NULL UNIQUE KEY
|
||||
* @return {@link TableCreateBuilder}
|
||||
*/
|
||||
default TableCreateBuilder addColumn(@NotNull String columnName, @NotNull String settings) {
|
||||
Objects.requireNonNull(columnName, "columnName could not be null");
|
||||
return addColumn(withBackQuote(columnName) + " " + settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* 为该表添加一个列
|
||||
*
|
||||
* @param columnName 列名
|
||||
* @param settings 列的设定
|
||||
* <br>如 VARCHAR(36) NOT NULL UNIQUE KEY
|
||||
* @param comments 列的注解,用于解释该列数据的作用
|
||||
* @return {@link TableCreateBuilder}
|
||||
*/
|
||||
default TableCreateBuilder addColumn(@NotNull String columnName, @NotNull String settings, @NotNull String comments) {
|
||||
return addColumn(columnName, settings + " COMMENT " + withQuote(comments));
|
||||
}
|
||||
|
||||
/**
|
||||
* 为该表添加一个自增列
|
||||
* <p> 自增列强制要求为数字类型,非空,且为UNIQUE。
|
||||
* <p> 注意:一个表只允许有一个自增列!
|
||||
*
|
||||
* @param columnName 列名
|
||||
* @param numberType 数字类型,若省缺则为 {@link NumberType#INT}
|
||||
* @param asPrimaryKey 是否为主键,若为false则设定为唯一键
|
||||
* @param unsigned 是否采用 UNSIGNED (即无负数,可以增加自增键的最高数,建议为true)
|
||||
* @return {@link TableCreateBuilder}
|
||||
*/
|
||||
TableCreateBuilder addAutoIncrementColumn(@NotNull String columnName, @Nullable NumberType numberType,
|
||||
boolean asPrimaryKey, boolean unsigned);
|
||||
|
||||
/**
|
||||
* 为该表添加一个INT类型的自增主键列
|
||||
* <p> 自增列强制要求为数字类型,非空,且为UNIQUE。
|
||||
* <p> 注意:一个表只允许有一个自增列!
|
||||
*
|
||||
* @param columnName 列名
|
||||
* @param asPrimaryKey 是否为主键,若为false则设定为唯一键
|
||||
* @param unsigned 是否采用 UNSIGNED (即无负数,可以增加自增键的最高数,建议为true)
|
||||
* @return {@link TableCreateBuilder}
|
||||
*/
|
||||
default TableCreateBuilder addAutoIncrementColumn(@NotNull String columnName,
|
||||
boolean asPrimaryKey, boolean unsigned) {
|
||||
return addAutoIncrementColumn(columnName, NumberType.INT, asPrimaryKey, unsigned);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 为该表添加一个INT类型的自增列
|
||||
* <p> 自增列强制要求为数字类型,非空,且为UNIQUE。
|
||||
* <p> 注意:一个表只允许有一个自增列!
|
||||
*
|
||||
* @param columnName 列名
|
||||
* @param asPrimaryKey 是否为主键,若为false则设定为唯一键
|
||||
* @return {@link TableCreateBuilder}
|
||||
*/
|
||||
default TableCreateBuilder addAutoIncrementColumn(@NotNull String columnName, boolean asPrimaryKey) {
|
||||
return addAutoIncrementColumn(columnName, asPrimaryKey, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 为该表添加一个INT类型的自增主键列
|
||||
* <p> 自增列强制要求为数字类型,非空,且为UNIQUE。
|
||||
* <p> 注意:一个表只允许有一个自增列!
|
||||
*
|
||||
* @param columnName 列名
|
||||
* @return {@link TableCreateBuilder}
|
||||
*/
|
||||
default TableCreateBuilder addAutoIncrementColumn(@NotNull String columnName) {
|
||||
return addAutoIncrementColumn(columnName, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设定表中的某列为索引或键。
|
||||
*
|
||||
* <p>创建索引时,你需要确保该索引是应用在 SQL 查询语句的条件(一般作为 WHERE 子句的条件)。
|
||||
* <br>虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE 和DELETE。
|
||||
* <br>因此,请合理的设计索引。
|
||||
*
|
||||
* @param type 索引类型
|
||||
* @param columnName 索引包含的列
|
||||
* @return {@link TableCreateBuilder}
|
||||
*/
|
||||
default TableCreateBuilder setIndex(@NotNull String columnName,
|
||||
@NotNull IndexType type) {
|
||||
return setIndex(type, null, columnName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设定表中的某列为索引或键。
|
||||
*
|
||||
* <p>创建索引时,你需要确保该索引是应用在 SQL 查询语句的条件(一般作为 WHERE 子句的条件)。
|
||||
* <br>虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE 和DELETE。
|
||||
* <br>因此,请合理的设计索引。
|
||||
*
|
||||
* @param type 索引类型
|
||||
* @param indexName 索引名称,缺省时将根据第一个索引列赋一个名称
|
||||
* @param columnName 索引包含的列
|
||||
* @param moreColumns 联合索引需要包含的列
|
||||
* @return {@link TableCreateBuilder}
|
||||
*/
|
||||
TableCreateBuilder setIndex(@NotNull IndexType type, @Nullable String indexName,
|
||||
@NotNull String columnName, @NotNull String... moreColumns);
|
||||
|
||||
|
||||
/**
|
||||
* 以本表位从表,为表中某列设定自参照外键(即自参照完整性)。
|
||||
*
|
||||
* <p>外键约束(FOREIGN KEY)是表的一个特殊字段,经常与主键约束一起使用。
|
||||
* <br>外键用来建立主表与从表的关联关系,为两个表的数据建立连接,约束两个表中数据的一致性和完整性。
|
||||
* <br>主表删除某条记录时,从表中与之对应的记录也必须有相应的改变。
|
||||
*
|
||||
* @param tableColumn 本表中的列
|
||||
* @param foreignColumn 外键关联表中对应的关联列,必须为目标表的主键,即 {@link IndexType#PRIMARY_KEY}
|
||||
* @return {@link TableCreateBuilder}
|
||||
*/
|
||||
default TableCreateBuilder addForeignKey(@NotNull String tableColumn, @NotNull String foreignColumn) {
|
||||
return addForeignKey(tableColumn, getTableName(), foreignColumn);
|
||||
}
|
||||
|
||||
/**
|
||||
* 以本表位从表,为表中某列设定外键。
|
||||
*
|
||||
* <p>外键约束(FOREIGN KEY)是表的一个特殊字段,经常与主键约束一起使用。
|
||||
* <br>外键用来建立主表与从表的关联关系,为两个表的数据建立连接,约束两个表中数据的一致性和完整性。
|
||||
* <br>主表删除某条记录时,从表中与之对应的记录也必须有相应的改变。
|
||||
*
|
||||
* @param tableColumn 本表中的列
|
||||
* @param foreignTable 外键关联主表,必须为已存在的表或本表,且必须有主键。
|
||||
* @param foreignColumn 外键关联主表中对应的关联列,须满足
|
||||
* <p> 1. 为主表的主键,即 {@link IndexType#PRIMARY_KEY}
|
||||
* <p> 2. 数据类型必须和所要建立主键的列的数据类型相同。
|
||||
* @return {@link TableCreateBuilder}
|
||||
*/
|
||||
default TableCreateBuilder addForeignKey(@NotNull String tableColumn,
|
||||
@NotNull String foreignTable, @NotNull String foreignColumn) {
|
||||
return addForeignKey(tableColumn, null, foreignTable, foreignColumn);
|
||||
}
|
||||
|
||||
/**
|
||||
* 以本表位从表,为表中某列设定外键。
|
||||
*
|
||||
* <p>外键约束(FOREIGN KEY)是表的一个特殊字段,经常与主键约束一起使用。
|
||||
* <br>外键用来建立主表与从表的关联关系,为两个表的数据建立连接,约束两个表中数据的一致性和完整性。
|
||||
* <br>主表删除某条记录时,从表中与之对应的记录也必须有相应的改变。
|
||||
*
|
||||
* @param tableColumn 本表中的列
|
||||
* @param constraintName 约束名,缺省时将使用参数自动生成,如 <i>fk_[tableColumn]_[foreignTable]</i>
|
||||
* @param foreignTable 外键关联主表,必须为已存在的表或本表,且必须有主键。
|
||||
* @param foreignColumn 外键关联主表中对应的关联列,须满足
|
||||
* <p> 1. 为主表的主键,即 {@link IndexType#PRIMARY_KEY}
|
||||
* <p> 2. 数据类型必须和所要建立主键的列的数据类型相同。
|
||||
* @return {@link TableCreateBuilder}
|
||||
*/
|
||||
default TableCreateBuilder addForeignKey(@NotNull String tableColumn, @Nullable String constraintName,
|
||||
@NotNull String foreignTable, @NotNull String foreignColumn) {
|
||||
return addForeignKey(tableColumn, constraintName, foreignTable, foreignColumn, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 以本表位从表,为表中某列设定外键。
|
||||
*
|
||||
* <p>外键约束(FOREIGN KEY)是表的一个特殊字段,经常与主键约束一起使用。
|
||||
* <br>外键用来建立主表与从表的关联关系,为两个表的数据建立连接,约束两个表中数据的一致性和完整性。
|
||||
* <br>主表删除某条记录时,从表中与之对应的记录也必须有相应的改变。
|
||||
*
|
||||
* @param tableColumn 本表中的列
|
||||
* @param constraintName 约束名,缺省时将使用参数自动生成,如 <i>fk_[tableColumn]_[foreignTable]</i>
|
||||
* @param foreignTable 外键关联主表,必须为已存在的表或本表,且必须有主键。
|
||||
* @param foreignColumn 外键关联主表中对应的关联列,须满足
|
||||
* <p> 1. 为主表的主键,即 {@link IndexType#PRIMARY_KEY}
|
||||
* <p> 2. 数据类型必须和所要建立主键的列的数据类型相同。
|
||||
* @param updateRule 在外键被更新时采用的规则,缺省时默认为{@link ForeignKeyRule#RESTRICT}
|
||||
* @param deleteRule 在外键被删除时采用的规则,缺省时默认为{@link ForeignKeyRule#RESTRICT}
|
||||
* @return {@link TableCreateBuilder}
|
||||
*/
|
||||
TableCreateBuilder addForeignKey(@NotNull String tableColumn, @Nullable String constraintName,
|
||||
@NotNull String foreignTable, @NotNull String foreignColumn,
|
||||
@Nullable ForeignKeyRule updateRule, @Nullable ForeignKeyRule deleteRule);
|
||||
|
||||
default String defaultTablesSettings() {
|
||||
return "ENGINE=InnoDB DEFAULT CHARSET=utf8";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.io.yutian.elementoriginlib.sql.api.builder;
|
||||
|
||||
import com.io.yutian.elementoriginlib.sql.api.SQLBuilder;
|
||||
import com.io.yutian.elementoriginlib.sql.api.function.SQLFunction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.Unmodifiable;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface TableMetadataBuilder extends SQLBuilder {
|
||||
|
||||
/**
|
||||
* @return 本表是否存在
|
||||
*/
|
||||
CompletableFuture<Boolean> validateExist();
|
||||
|
||||
/**
|
||||
* 对表内的数据列元数据进行读取
|
||||
*
|
||||
* @param columnPattern 列的名称匹配表达式, 为空则匹配所有列
|
||||
* @param reader 读取的方法
|
||||
* @param <R> 结果类型
|
||||
* @return 读取结果
|
||||
*/
|
||||
<R> CompletableFuture<R> fetchColumns(@Nullable String columnPattern,
|
||||
@NotNull SQLFunction<ResultSet, R> reader);
|
||||
|
||||
/**
|
||||
* @param columnPattern 需要判断的列名表达式
|
||||
* @return 对应列是否存在
|
||||
*/
|
||||
CompletableFuture<Boolean> isColumnExists(@NotNull String columnPattern);
|
||||
|
||||
/**
|
||||
* 列出所有表内的全部列。
|
||||
*
|
||||
* @return 表内全部数据列的列名
|
||||
*/
|
||||
default CompletableFuture<@Unmodifiable Set<String>> listColumns() {
|
||||
return listColumns(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 列出所有满足表达式的列。
|
||||
*
|
||||
* @param columnPattern 列名表达式,为空则列出全部
|
||||
* @return 所有满足表达式的列名
|
||||
*/
|
||||
CompletableFuture<@Unmodifiable Set<String>> listColumns(@Nullable String columnPattern);
|
||||
|
||||
// More coming soon.
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user