This commit is contained in:
YuTian 2024-07-27 17:08:05 +08:00
commit f57af31969
162 changed files with 18234 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/.idea/
/target/
/ElementOriginLib.iml

140
pom.xml Normal file
View 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>

View File

@ -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;
}
}

View File

@ -0,0 +1,8 @@
package com.io.yutian.elementoriginlib.command;
@FunctionalInterface
public interface Command<S extends CommandContext> {
void run(S context);
}

View File

@ -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));
}
}

View File

@ -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);
}
}

View File

@ -0,0 +1,7 @@
package com.io.yutian.elementoriginlib.command;
public interface IAlias {
String[] getAlias();
}

View File

@ -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;
}
}

View File

@ -0,0 +1,11 @@
package com.io.yutian.elementoriginlib.command;
import java.util.List;
public interface ICommandManager {
String getName();
List<ICommand> getCommands();
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}
}

View File

@ -0,0 +1,10 @@
package com.io.yutian.elementoriginlib.command;
import java.util.List;
@FunctionalInterface
public interface Suggest {
List<String> getSuggest();
}

View File

@ -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;
};
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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 +
'}';
}
}

View File

@ -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);
}
}

View File

@ -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";
}
}

View File

@ -0,0 +1,9 @@
package com.io.yutian.elementoriginlib.exception;
public class SerializeException extends RuntimeException {
public SerializeException(Class clazz, Throwable cause) {
super(clazz.toString());
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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 + '}';
}
}

View File

@ -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());
}
}

View File

@ -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;
}
}

View 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;
}
}

View File

@ -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);
}
}
}
}

View 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;
}
}

View File

@ -0,0 +1,9 @@
package com.io.yutian.elementoriginlib.gui;
import org.bukkit.event.inventory.InventoryDragEvent;
public interface IGuiDrag {
void onInventoryDrag(InventoryDragEvent event);
}

View 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;
}
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -0,0 +1,9 @@
package com.io.yutian.elementoriginlib.gui.button;
public enum ClickType {
LEFT_CLICK,
RIGHT_CLICK,
SHIFT_CLICK
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View 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;
}
}

View 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);
}
}

View File

@ -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);
}
}
}
}

View File

@ -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);
}
}

View 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;
}
}

View File

@ -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 +
'}';
}
}

View File

@ -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) +
'}';
}
}

View File

@ -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 +
'}';
}
}

View File

@ -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 +
'}';
}
}

View File

@ -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 +
'}';
}
}

View File

@ -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);
}
}

View 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 +
'}';
}
}

View File

@ -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);
}
}

View File

@ -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));
}
}

View File

@ -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 +
'}';
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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 +
'}';
}
}

View File

@ -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 + '\'' +
'}';
}
}

View File

@ -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"));
}
}

View 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);
}
}

View File

@ -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());
}
}

View File

@ -0,0 +1,9 @@
package com.io.yutian.elementoriginlib.redis;
import redis.clients.jedis.Jedis;
public interface IJedisGetter {
Jedis getRedis();
}

View File

@ -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;
}
}
}

View File

@ -0,0 +1,8 @@
package com.io.yutian.elementoriginlib.redis;
@FunctionalInterface
public interface RedisCacheSynchronizer {
void sync(String key, String data);
}

View File

@ -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();
}
}

View File

@ -0,0 +1,11 @@
package com.io.yutian.elementoriginlib.serialize;
import org.json.JSONObject;
public interface ISerializable<T> {
JSONObject serialize();
T deserialize(JSONObject jsonObject);
}

View File

@ -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());
}
}

View File

@ -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 {
}

View File

@ -0,0 +1,9 @@
package com.io.yutian.elementoriginlib.serialize;
public interface Serializer<T> {
Object serialize(T value);
T deserialize(Object value);
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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());
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}
}
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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());
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
});
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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();
}

View File

@ -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语句(多用于UPDATEREPLACEDELETE方法)
* 该方法使用 Statement 实现请注意SQL注入风险
*
* @param sql SQL语句内容
* @return 更新的行数
* @see SQLUpdateAction
*/
@Nullable Integer executeSQL(String sql);
/**
* 执行一条不需要返回结果的预处理SQL更改(UPDATEREPLACEDELETE)
*
* @param sql SQL语句内容
* @param params SQL语句中 ? 的对应参数
* @return 更新的行数
* @see PreparedSQLUpdateAction
*/
@Nullable Integer executeSQL(String sql, Object[] params);
/**
* 执行多条不需要返回结果的SQL更改(UPDATEREPLACEDELETE)
*
* @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);
}

View File

@ -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();
}

View File

@ -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());
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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;
}
}
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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));
}
}

View File

@ -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);
}

View File

@ -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));
}
}

View File

@ -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);
}
}

View File

@ -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>虽然索引大大提高了查询速度同时却会降低更新表的速度如对表进行INSERTUPDATE 和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>虽然索引大大提高了查询速度同时却会降低更新表的速度如对表进行INSERTUPDATE 和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";
}
}

View File

@ -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