修改了 RedisBungeeUtil.java 文件,修复了一些逻辑错误并优化了性能。

This commit is contained in:
YuTian 2025-05-11 14:59:31 +08:00
parent 1de44ba982
commit 0eb25bcbb0
62 changed files with 2357 additions and 2413 deletions

22
pom.xml
View File

@ -137,5 +137,27 @@
<artifactId>jedis</artifactId> <artifactId>jedis</artifactId>
<version>5.2.0</version> <version>5.2.0</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/net.jodah/expiringmap -->
<dependency>
<groupId>net.jodah</groupId>
<artifactId>expiringmap</artifactId>
<version>0.5.11</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.javassist/javassist -->
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.30.2-GA</version>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-sync</artifactId>
<version>5.4.0</version>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-reactivestreams</artifactId>
<version>5.4.0</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -8,14 +8,12 @@ import com.io.yutian.elementoriginlib.logger.Logger;
import com.io.yutian.elementoriginlib.manager.CommandManager; import com.io.yutian.elementoriginlib.manager.CommandManager;
import com.io.yutian.elementoriginlib.redis.RedisIO; import com.io.yutian.elementoriginlib.redis.RedisIO;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.slf4j.LoggerFactory;
public final class ElementOriginLib extends JavaPlugin { public final class ElementOriginLib extends JavaPlugin {
private static final org.slf4j.Logger log = LoggerFactory.getLogger(ElementOriginLib.class); public static final Logger LOGGER = Logger.getLogger(ElementOriginLib.class);
private static ElementOriginLib instance;
private static Logger logger = Logger.getLogger(ElementOriginLib.class); private static ElementOriginLib instance;
private RedisIO redisIO; private RedisIO redisIO;
@ -39,6 +37,7 @@ public final class ElementOriginLib extends JavaPlugin {
@Override @Override
public void onDisable() { public void onDisable() {
redisIO.close();
} }
public void reload() { public void reload() {

View File

@ -5,7 +5,7 @@ import com.io.yutian.elementoriginlib.command.argument.ArgumentType;
import com.io.yutian.elementoriginlib.command.interfaces.Command; import com.io.yutian.elementoriginlib.command.interfaces.Command;
import com.io.yutian.elementoriginlib.command.interfaces.Parameter; import com.io.yutian.elementoriginlib.command.interfaces.Parameter;
import com.io.yutian.elementoriginlib.command.interfaces.SubCommand; import com.io.yutian.elementoriginlib.command.interfaces.SubCommand;
import com.io.yutian.elementoriginlib.exception.command.CommandParseException; import com.io.yutian.elementoriginlib.exception.CommandParseException;
import com.io.yutian.elementoriginlib.logger.Logger; import com.io.yutian.elementoriginlib.logger.Logger;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -20,13 +20,15 @@ public class CommandEntity {
private String command; private String command;
private String permission; private String permission;
private List<SenderRequire> senderRequires;
private List<CommandEntry> childrens = new ArrayList<>(); private List<CommandEntry> childrens = new ArrayList<>();
public CommandEntity(Object instance, String command, String permission, List<CommandEntry> childrens) { public CommandEntity(Object instance, String command, String permission, List<SenderRequire> senderRequires, List<CommandEntry> childrens) {
this.instance = instance; this.instance = instance;
this.command = command; this.command = command;
this.permission = permission; this.permission = permission;
this.senderRequires = senderRequires;
this.childrens = childrens; this.childrens = childrens;
} }
@ -46,11 +48,23 @@ public class CommandEntity {
return permission; return permission;
} }
public List<SenderRequire> getSenderRequires() {
return senderRequires;
}
public List<CommandEntry> getChildrens() { public List<CommandEntry> getChildrens() {
return childrens; return childrens;
} }
public boolean canInvoke(CommandSender sender) { public boolean canInvoke(CommandSender sender) {
if (senderRequires != null && senderRequires.size() > 0) {
for (SenderRequire senderRequire : senderRequires) {
if (senderRequire.test(sender)) {
return true;
}
}
return false;
}
if (childrens.size() == 1 && childrens.get(0).isNodal()) { if (childrens.size() == 1 && childrens.get(0).isNodal()) {
CommandEntry child = childrens.get(0); CommandEntry child = childrens.get(0);
return child.canInvoke(sender); return child.canInvoke(sender);
@ -74,17 +88,18 @@ public class CommandEntity {
throw new CommandParseException("" + clazz + " 未标注 @Command 注解"); throw new CommandParseException("" + clazz + " 未标注 @Command 注解");
} }
// Object instance;
// try {
// instance = clazz.getConstructor(null).newInstance();
// } catch (Exception e) {
// e.printStackTrace();
// throw new CommandParseException("无法实例化类 "+clazz);
// }
Command commandAnnotation = (Command) clazz.getAnnotation(Command.class); Command commandAnnotation = (Command) clazz.getAnnotation(Command.class);
String command = commandAnnotation.value(); String command = commandAnnotation.value();
String permission = commandAnnotation.permission(); String permission = commandAnnotation.permission();
String[] senderRequireArray = commandAnnotation.senderRequire();
List<SenderRequire> senderRequireList = new ArrayList<>();
for (String senderRequire : senderRequireArray) {
SenderRequire senderRequire1 = SenderRequires.get(senderRequire);
if (senderRequire1 == null) {
throwParseException(clazz, "使用者权限 " + senderRequire + " 不存在");
}
senderRequireList.add(SenderRequires.get(senderRequire));
}
List<CommandEntry> allEntries = new ArrayList<>(); List<CommandEntry> allEntries = new ArrayList<>();
Map<String, CommandEntry> pathToEntryMap = new HashMap<>(); Map<String, CommandEntry> pathToEntryMap = new HashMap<>();
@ -153,7 +168,7 @@ public class CommandEntity {
return null; return null;
} }
return new CommandEntity(instance, command, permission, rootEntries); return new CommandEntity(instance, command, permission, senderRequireList, rootEntries);
} }
@ -222,9 +237,20 @@ public class CommandEntity {
Parameter commandArgument = parameter.getAnnotation(Parameter.class); Parameter commandArgument = parameter.getAnnotation(Parameter.class);
String name = commandArgument.name(); String name = commandArgument.name();
String argumentName = name.isEmpty() ? parameter.getName() : name; String argumentName = name.isEmpty() ? parameter.getName() : name;
boolean required = commandArgument.required(); boolean optional = commandArgument.optional();
if (!required && index < allArgumentsCount - 1) { if (optional) {
throwParseException(clazz, "可选参数仅能在最后一个位置中使用"); boolean flag = true;
for (int i = index; i < allArgumentsCount; i++) {
java.lang.reflect.Parameter parameter1 = method.getParameters()[i];
Parameter parameterAnnotation = parameter.getAnnotation(Parameter.class);
if (!parameterAnnotation.optional()) {
flag = false;
break;
}
}
if (!flag) {
throwParseException(clazz, "可选参数错误, 后续参数必须都是是可选参数");
}
} }
String defaultValue = commandArgument.defaultValue(); String defaultValue = commandArgument.defaultValue();
String suggestionType = commandArgument.suggestionType(); String suggestionType = commandArgument.suggestionType();
@ -242,7 +268,7 @@ public class CommandEntity {
argument.suggest(suggest); argument.suggest(suggest);
} }
} }
if (!required) { if (optional) {
argument.optional(defaultValue); argument.optional(defaultValue);
} }
arguments.add(argument); arguments.add(argument);

View File

@ -6,6 +6,8 @@ public interface ICommandManager {
String getName(); String getName();
String getPluginId();
List<CommandEntity> getCommandEntities(); List<CommandEntity> getCommandEntities();
} }

View File

@ -65,6 +65,11 @@ public class SimpleCommandManager implements ICommandManager {
return name; return name;
} }
@Override
public String getPluginId() {
return name.toLowerCase();
}
@NotNull @NotNull
@Override @Override
public List<CommandEntity> getCommandEntities() { public List<CommandEntity> getCommandEntities() {

View File

@ -8,6 +8,7 @@ import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Supplier;
public class Suggests { public class Suggests {
@ -41,6 +42,51 @@ public class Suggests {
suggests.remove(name); suggests.remove(name);
} }
public static Suggest createEnumSuggest(Class<? extends Enum> enumClass) {
return new EnumSuggest(enumClass);
}
public static Suggest createListSuggest(Supplier<List<String>> supplier) {
return new ListSuggest(supplier);
}
private static class EnumSuggest implements Suggest {
private List<String> suggestions = new LinkedList<>();
private Class<? extends Enum> enumClass;
public EnumSuggest(Class<? extends Enum> enumClass) {
this.enumClass = enumClass;
if (enumClass != null && enumClass.isEnum()) {
Enum<?>[] constants = enumClass.getEnumConstants();
if (constants != null) {
for (Enum<?> enumConstant : constants) {
suggestions.add(enumConstant.name());
}
}
}
}
@Override
public List<String> getSuggest() {
return suggestions;
}
}
private static class ListSuggest implements Suggest {
private Supplier<List<String>> supplier;
public ListSuggest(Supplier<List<String>> supplier) {
this.supplier = supplier;
}
@Override
public List<String> getSuggest() {
return supplier.get();
}
}
static { static {
registerSuggest("world_list", WORLD_LIST); registerSuggest("world_list", WORLD_LIST);

View File

@ -16,6 +16,8 @@ public class ArgumentType<T> {
private static final ArgumentType<Double> DOUBLE = new ArgumentType<>("double", StringUtil::isDouble, Double::parseDouble); private static final ArgumentType<Double> DOUBLE = new ArgumentType<>("double", StringUtil::isDouble, Double::parseDouble);
private static final ArgumentType<Float> FLOAT = new ArgumentType<>("float", StringUtil::isFloat, Float::parseFloat);
private static final ArgumentType<Boolean> BOOLEAN = new ArgumentType<>("boolean", StringUtil::isBoolean, Boolean::parseBoolean); private static final ArgumentType<Boolean> BOOLEAN = new ArgumentType<>("boolean", StringUtil::isBoolean, Boolean::parseBoolean);
private static final ArgumentType<String[]> STRING_ARRAY = new ArgumentType<>("string[]", (s) -> true, (s) -> s.split(",")); private static final ArgumentType<String[]> STRING_ARRAY = new ArgumentType<>("string[]", (s) -> true, (s) -> s.split(","));
@ -74,6 +76,7 @@ public class ArgumentType<T> {
register(String.class, STRING); register(String.class, STRING);
register(Integer.class, INTEGER); register(Integer.class, INTEGER);
register(Double.class, DOUBLE); register(Double.class, DOUBLE);
register(Float.class, FLOAT);
register(Boolean.class, BOOLEAN); register(Boolean.class, BOOLEAN);
register(String[].class, STRING_ARRAY); register(String[].class, STRING_ARRAY);
register(Integer[].class, INTEGER_ARRAY); register(Integer[].class, INTEGER_ARRAY);
@ -97,20 +100,17 @@ public class ArgumentType<T> {
return (ArgumentType<T>) ARGUMENT_TYPES.get(c); return (ArgumentType<T>) ARGUMENT_TYPES.get(c);
} }
private static class EnumArgumentType<T extends Enum<T>> extends ArgumentType<T> { public static class EnumArgumentType<T extends Enum<T>> extends ArgumentType<T> {
private final Class<T> clazz;
public EnumArgumentType(String name, Class<T> clazz) { public EnumArgumentType(String name, Class<T> clazz) {
super(name, (s)->{ super(name, (s)->{
try { try {
Enum.valueOf(clazz, s); Enum.valueOf(clazz, s.toUpperCase());
return true; return true;
} catch (Exception e) { } catch (Exception e) {
return false; return false;
} }
}, (s)-> Enum.valueOf(clazz, s)); }, (s)-> Enum.valueOf(clazz, s.toUpperCase()));
this.clazz = clazz;
} }
} }

View File

@ -74,12 +74,12 @@ public class CommandHandler implements CommandExecutor, TabCompleter {
if (!entry.getChildrens().isEmpty()) { if (!entry.getChildrens().isEmpty()) {
fullCommand.append(" "); fullCommand.append(" ");
handleCommand(commandEntity, sender, label, args, entry.getChildrens(), index + 1, fullCommand); handleCommand(commandEntity, sender, label, args, entry.getChildrens(), index, fullCommand);
} else { } else {
if (!validateArguments(sender, entry.getArguments(), args, index + 1)) { if (!validateArguments(sender, entry.getArguments(), args, index)) {
return; return;
} }
Map<String, ArgumentValue> parsedArguments = parseArgumentValue(sender, entry.getArguments(), args, index + 1); Map<String, ArgumentValue> parsedArguments = parseArgumentValue(sender, entry.getArguments(), args, index);
entry.invoke(new CommandContext(commandEntity.getInstance(), fullCommand.toString(), label, sender, parsedArguments)); entry.invoke(new CommandContext(commandEntity.getInstance(), fullCommand.toString(), label, sender, parsedArguments));
} }
} }
@ -87,7 +87,7 @@ public class CommandHandler implements CommandExecutor, TabCompleter {
private boolean validateArguments(CommandSender sender, List<Argument> arguments, String[] args, int startIndex) { private boolean validateArguments(CommandSender sender, List<Argument> arguments, String[] args, int startIndex) {
for (int i = 0; i < arguments.size(); i++) { for (int i = 0; i < arguments.size(); i++) {
Argument argument = arguments.get(i); Argument argument = arguments.get(i);
int argIndex = startIndex + i; int argIndex = startIndex + i + 1;
if (argIndex >= args.length) { if (argIndex >= args.length) {
if (argument.isOptional()) { if (argument.isOptional()) {
continue; continue;
@ -109,36 +109,26 @@ public class CommandHandler implements CommandExecutor, TabCompleter {
Map<String, ArgumentValue> parsedArguments = new HashMap<>(); Map<String, ArgumentValue> parsedArguments = new HashMap<>();
List<Object> methodParams = new ArrayList<>(); List<Object> methodParams = new ArrayList<>();
int pIndex = startIndex + 1;
for (int argIndex = 0; argIndex < arguments.size(); argIndex++) { for (int argIndex = 0; argIndex < arguments.size(); argIndex++) {
Argument argument = arguments.get(argIndex); Argument argument = arguments.get(argIndex);
if (argIndex >= args.length) {
if (!argument.isOptional()) {
sender.sendMessage(Lang.get("command.short-arg", argument.getName()));
return null;
}
}
String rawValue = null; String rawValue = null;
if (argument.isOptional() && argIndex >= args.length) { if (argument.isOptional() && pIndex >= args.length) {
rawValue = argument.getDefaultValue(); rawValue = argument.getDefaultValue();
} else { } else {
rawValue = args[argIndex + startIndex]; rawValue = args[pIndex];
}
if (!argument.getArgumentsType().test(rawValue)) {
sender.sendMessage(Lang.get("command.error-arg", argIndex + 1, rawValue));
return null;
} }
Object parsedValue = argument.getArgumentsType().get(rawValue); Object parsedValue = argument.getArgumentsType().get(rawValue);
parsedArguments.put(argument.getName(), new ArgumentValue(parsedValue)); parsedArguments.put(argument.getName(), new ArgumentValue(parsedValue));
methodParams.add(parsedValue); methodParams.add(parsedValue);
pIndex++;
} }
return parsedArguments; return parsedArguments;
} }
@Override @Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
long startTime = System.currentTimeMillis();
execute(sender, label, args); execute(sender, label, args);
return true; return true;
} }
@ -161,21 +151,23 @@ public class CommandHandler implements CommandExecutor, TabCompleter {
} }
CommandEntity commandEntity = entityOptional.get(); CommandEntity commandEntity = entityOptional.get();
List<CommandEntry> entries = commandEntity.getChildrens();
if (entries.isEmpty()) { if (commandEntity == null) {
return Collections.emptyList(); return Collections.emptyList();
} }
int depth = args.length; int depth = args.length;
String currentArg = args[depth - 1]; int index = depth - 1;
return getSuggestions(sender, entries, args, 0, depth - 1, currentArg); String currentArg = args[index];
return getSuggestions(sender, commandEntity, args, 0, index, currentArg);
} }
private List<String> getSuggestions(CommandSender sender, List<CommandEntry> entries, String[] args, int start, int currentDepth, String currentArg) { private List<String> getSuggestions(CommandSender sender, CommandEntity commandEntity, String[] args, int start, int currentDepth, String currentArg) {
CommandEntry commandEntry = null; CommandEntry commandEntry = null;
List<CommandEntry> entries = commandEntity.getChildrens();
for (int i = start; i < currentDepth; i++) { for (int i = start; i < currentDepth; i++) {
String arg = args[i]; String arg = args[i];
@ -192,10 +184,14 @@ public class CommandHandler implements CommandExecutor, TabCompleter {
entries = commandEntry.getChildrens(); entries = commandEntry.getChildrens();
} }
int pIndex = 2;
if (commandEntry != null && commandEntry.isNodal()) {
pIndex = 1;
}
if (entries.size() == 0) { if (entries.size() == 0) {
List<Argument> arguments = commandEntry.getArguments(); List<Argument> arguments = commandEntry.getArguments();
int index = (int) (currentDepth - commandEntry.getDepth() - 2); int index = (int) (currentDepth - commandEntry.getDepth() - pIndex);
if (index >= arguments.size()) { if (index >= arguments.size()) {
return Collections.emptyList(); return Collections.emptyList();
} }

View File

@ -13,4 +13,6 @@ public @interface Command {
String permission() default "command.elementoriginlib.default"; String permission() default "command.elementoriginlib.default";
String[] senderRequire() default { "console", "player" };
} }

View File

@ -11,7 +11,7 @@ public @interface Parameter {
String name() default ""; String name() default "";
boolean required() default true; boolean optional() default false;
String defaultValue() default ""; String defaultValue() default "";

View File

@ -33,7 +33,7 @@ public class CommandHelp {
} }
@SubCommand(nodal = true) @SubCommand(nodal = true)
public void help(CommandContext commandContext, @Parameter(required = false, defaultValue = "1") int page) { public void help(CommandContext commandContext, @Parameter(optional = true, defaultValue = "1") int page) {
String alias = commandContext.getLabel(); String alias = commandContext.getLabel();
String commandAlias = alias != null ? alias : commandContext.getLabel(); String commandAlias = alias != null ? alias : commandContext.getLabel();
CommandSender sender = commandContext.getSender(); CommandSender sender = commandContext.getSender();
@ -87,6 +87,9 @@ public class CommandHelp {
} }
} }
Optional<String> optional = Lang.getOptional("command."+command.getCommand()+".description"); Optional<String> optional = Lang.getOptional("command."+command.getCommand()+".description");
if (!optional.isPresent()) {
optional = Lang.getOptional(commandManager.getPluginId()+".command."+command.getCommand()+".description");
}
if (optional.isPresent()) { if (optional.isPresent()) {
stringBuilder.append(" "); stringBuilder.append(" ");
stringBuilder.append("§7- §f"+ optional.get()); stringBuilder.append("§7- §f"+ optional.get());

View File

@ -7,6 +7,13 @@ public class OriginLibConfig {
private String redisBungeeNetworkId; private String redisBungeeNetworkId;
private String redisBungeeProxyId; private String redisBungeeProxyId;
private String mongoDbHost;
private int mongoDbPort;
private String mongoDbDatabase;
private String mongoDbUsername;
private String mongoDbPassword;
public void load(FileConfiguration config) { public void load(FileConfiguration config) {
redisBungeeNetworkId = config.getString("redisBungeeNetworkId"); redisBungeeNetworkId = config.getString("redisBungeeNetworkId");
redisBungeeProxyId = config.getString("redisBungeeProxyId"); redisBungeeProxyId = config.getString("redisBungeeProxyId");

View File

@ -1,4 +1,4 @@
package com.io.yutian.elementoriginlib.exception.command; package com.io.yutian.elementoriginlib.exception;
public class CommandParseException extends RuntimeException { public class CommandParseException extends RuntimeException {

View File

@ -1,4 +1,4 @@
package com.io.yutian.elementoriginlib.exception.itemstat; package com.io.yutian.elementoriginlib.exception;
public class ItemStatDataLoadException extends RuntimeException { public class ItemStatDataLoadException extends RuntimeException {

View File

@ -1,17 +0,0 @@
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

@ -1,17 +0,0 @@
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

@ -1,15 +0,0 @@
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

@ -1,17 +0,0 @@
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);
}

View File

@ -1,122 +0,0 @@
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
* @throws NullPointerException on null timeUnit
* @see ExpiringMap#put(Object, Object, long, 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
* @throws NullPointerException on null timeUnit
* @see ExpiringMap#put(Object, Object, ExpirationPolicy, long, 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

@ -1,32 +0,0 @@
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

@ -1,27 +0,0 @@
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,55 @@
package com.io.yutian.elementoriginlib.gui;
import com.io.yutian.elementoriginlib.util.ItemStackBuilder;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class DebugGui extends Gui {
private Set<Integer> cachedSlots = new HashSet<>();
public DebugGui(Player player, int size) {
super(player, Component.text("Debug Gui"), size);
}
@Override
public void init() {
}
@Override
public void close(InventoryCloseEvent event) {
StringBuilder sb = new StringBuilder();
int i = 0;
List<Integer> list = new ArrayList<>(cachedSlots);
list.sort(Integer::compareTo);
for (int slot : list) {
sb.append(slot);
if (i < list.size() - 1) {
sb.append(", ");
}
i++;
}
player.sendMessage(Component.text("§b["+sb.toString()+"]").clickEvent(ClickEvent.clickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, sb.toString())).hoverEvent(Component.text("§f§l[点击复制]")));
}
@Override
public void handler(Player player, int slot, InventoryClickEvent event) {
if (slot < inventory.getSize()) {
if (!cachedSlots.contains(slot)) {
cachedSlots.add(slot);
inventory.setItem(slot, new ItemStackBuilder(Material.SLIME_BALL).setDisplayName(" ").setDisplayName("§a"+slot).build());
}
event.setCancelled(true);
}
}
}

View File

@ -13,7 +13,7 @@ import org.bukkit.event.inventory.InventoryClickEvent;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
public class Gui extends IGui { public abstract class Gui extends IGui {
public Map<Integer, Button> buttons = new HashMap<>(); public Map<Integer, Button> buttons = new HashMap<>();
@ -21,10 +21,6 @@ public class Gui extends IGui {
super(player, title, size); super(player, title, size);
} }
@Override
public void init() {
}
@Override @Override
public void handler(Player player, int slot, InventoryClickEvent event) { public void handler(Player player, int slot, InventoryClickEvent event) {
if (buttons.containsKey(slot)) { if (buttons.containsKey(slot)) {

View File

@ -38,6 +38,7 @@ public abstract class IGui implements InventoryHolder {
} }
public void open() { public void open() {
init();
player.openInventory(inventory); player.openInventory(inventory);
} }

View File

@ -13,7 +13,7 @@ import org.bukkit.event.inventory.InventoryClickEvent;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
public class PageGui extends IGui { public abstract class PageGui extends IGui {
private int page = 1; private int page = 1;
private int maxPage; private int maxPage;
@ -25,6 +25,13 @@ public class PageGui extends IGui {
this.maxPage = maxPage; this.maxPage = maxPage;
} }
@Override
public void open() {
init();
initButton();
player.openInventory(inventory);
}
public void initButton() { public void initButton() {
initButton(this.page); initButton(this.page);
} }
@ -63,10 +70,6 @@ public class PageGui extends IGui {
} }
} }
@Override
public void init() {
}
@Override @Override
public void handler(Player player, int slot, InventoryClickEvent event) { public void handler(Player player, int slot, InventoryClickEvent event) {
if (pages.containsKey(page)) { if (pages.containsKey(page)) {

View File

@ -24,16 +24,40 @@ public class TagStatItem {
this.builder = new TagStatItemStackBuilder(this); this.builder = new TagStatItemStackBuilder(this);
} }
public void setStatData(@NotNull Class<? extends ItemStat> statClass, @NotNull StatData data) {
ItemStat itemStat = ItemStats.getItemStat(statClass);
if (itemStat == null) {
return;
}
setStatData(itemStat, data);
}
public void setStatData(@NotNull ItemStat stat, @NotNull StatData data) { public void setStatData(@NotNull ItemStat stat, @NotNull StatData data) {
this.stats.put(stat, data); this.stats.put(stat, data);
this.itemStack = builder().build(); this.itemStack = builder().build();
} }
public void removeStatData(@NotNull Class<? extends ItemStat> statClass) {
ItemStat itemStat = ItemStats.getItemStat(statClass);
if (itemStat == null) {
return;
}
removeStatData(itemStat);
}
public void removeStatData(@NotNull ItemStat stat) { public void removeStatData(@NotNull ItemStat stat) {
this.stats.remove(stat); this.stats.remove(stat);
this.itemStack = builder().build(); this.itemStack = builder().build();
} }
public <S extends StatData> S getStatData(@NotNull Class<? extends ItemStat<S>> statClass) {
ItemStat itemStat = ItemStats.getItemStat(statClass);
if (itemStat == null) {
return null;
}
return (S) getStatData(itemStat);
}
public <S extends StatData> S getStatData(@NotNull ItemStat<S> stat) { public <S extends StatData> S getStatData(@NotNull ItemStat<S> stat) {
if (!hasStatData(stat)) { if (!hasStatData(stat)) {
stat.load(this); stat.load(this);
@ -41,6 +65,14 @@ public class TagStatItem {
return (S) this.stats.get(stat); return (S) this.stats.get(stat);
} }
public boolean hasStatData(@NotNull Class<? extends ItemStat> statClass) {
ItemStat itemStat = ItemStats.getItemStat(statClass);
if (itemStat == null) {
return false;
}
return hasStatData(itemStat);
}
public boolean hasStatData(@NotNull ItemStat stat) { public boolean hasStatData(@NotNull ItemStat stat) {
if (!this.stats.containsKey(stat)) { if (!this.stats.containsKey(stat)) {
try { try {

View File

@ -2,13 +2,9 @@ package com.io.yutian.elementoriginlib.item;
import com.io.yutian.elementoriginlib.tag.ItemProxy; import com.io.yutian.elementoriginlib.tag.ItemProxy;
import com.io.yutian.elementoriginlib.tag.TagCompound; import com.io.yutian.elementoriginlib.tag.TagCompound;
import net.kyori.adventure.text.Component;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
public class TagStatItemStackBuilder { public class TagStatItemStackBuilder {
@ -16,14 +12,12 @@ public class TagStatItemStackBuilder {
private final TagStatItem tagStatItem; private final TagStatItem tagStatItem;
protected ItemStack itemStack; protected ItemStack itemStack;
protected ItemMeta itemMeta;
protected ItemProxy itemProxy; protected ItemProxy itemProxy;
public TagStatItemStackBuilder(TagStatItem tagStatItem) { public TagStatItemStackBuilder(TagStatItem tagStatItem) {
this.tagStatItem = tagStatItem; this.tagStatItem = tagStatItem;
this.itemStack = tagStatItem.getItemStack(); this.itemStack = tagStatItem.getItemStack();
this.itemMeta = itemStack.getItemMeta();
this.itemProxy = tagStatItem.getItemProxy(); this.itemProxy = tagStatItem.getItemProxy();
} }
@ -37,20 +31,10 @@ public class TagStatItemStackBuilder {
return itemStack; return itemStack;
} }
@NotNull
public ItemMeta getItemMeta() {
return itemMeta;
}
private void buildCompounds() { private void buildCompounds() {
tagStatItem.getStats().forEach((stat, statData) -> stat.whenApplied(this, statData)); tagStatItem.getStats().forEach((stat, statData) -> stat.whenApplied(this, statData));
itemStack = itemProxy.getItemStack(); itemStack = itemProxy.getItemStack();
itemMeta = itemStack.getItemMeta();
tagStatItem.getStats().forEach((stat, statData) -> stat.applyMeta(this, statData)); tagStatItem.getStats().forEach((stat, statData) -> stat.applyMeta(this, statData));
List<Component> lores = itemMeta.hasLore() ? itemMeta.lore() : new ArrayList<>();
tagStatItem.getStats().forEach((stat, statData) -> stat.whenApplyLore(this, statData, lores));
itemMeta.lore(lores);
itemStack.setItemMeta(itemMeta);
} }
@NotNull @NotNull
@ -58,6 +42,10 @@ public class TagStatItemStackBuilder {
return itemProxy; return itemProxy;
} }
public ItemStack getItemStack() {
return itemStack;
}
public TagStatItem getOriginItem() { public TagStatItem getOriginItem() {
return tagStatItem; return tagStatItem;
} }

View File

@ -1,14 +1,11 @@
package com.io.yutian.elementoriginlib.item.stat; package com.io.yutian.elementoriginlib.item.stat;
import com.io.yutian.elementoriginlib.exception.itemstat.ItemStatDataLoadException;
import com.io.yutian.elementoriginlib.item.TagStatItem; import com.io.yutian.elementoriginlib.item.TagStatItem;
import com.io.yutian.elementoriginlib.item.TagStatItemStackBuilder; import com.io.yutian.elementoriginlib.item.TagStatItemStackBuilder;
import com.io.yutian.elementoriginlib.tag.ItemProxy; import com.io.yutian.elementoriginlib.tag.ItemProxy;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.List;
public abstract class ItemStat<S extends StatData> { public abstract class ItemStat<S extends StatData> {
@NotNull @NotNull
@ -23,14 +20,9 @@ public abstract class ItemStat<S extends StatData> {
public abstract void whenApplied(@NotNull TagStatItemStackBuilder itemStackBuilder, @NotNull S statData); public abstract void whenApplied(@NotNull TagStatItemStackBuilder itemStackBuilder, @NotNull S statData);
public abstract S loadAsObject(@NotNull Object value) throws ItemStatDataLoadException;
public void applyMeta(@NotNull TagStatItemStackBuilder itemStackBuilder, @NotNull S statData) { public void applyMeta(@NotNull TagStatItemStackBuilder itemStackBuilder, @NotNull S statData) {
} }
public void whenApplyLore(@NotNull TagStatItemStackBuilder itemStackBuilder, @NotNull S statData, @NotNull List<String> lores) {
}
@Nullable @Nullable
public abstract S getLoadedTag(@NotNull ItemProxy itemProxy); public abstract S getLoadedTag(@NotNull ItemProxy itemProxy);

View File

@ -4,10 +4,7 @@ import com.io.yutian.elementoriginlib.item.stat.list.IdStat;
import com.io.yutian.elementoriginlib.logger.Logger; import com.io.yutian.elementoriginlib.logger.Logger;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Collection; import java.util.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class ItemStats { public class ItemStats {
@ -21,13 +18,28 @@ public class ItemStats {
public static void register(ItemStat itemStat) { public static void register(ItemStat itemStat) {
Class<? extends ItemStat> clazz = itemStat.getClass(); Class<? extends ItemStat> clazz = itemStat.getClass();
if (itemStats.containsKey(itemStat.getId())) { if (isRegistered(itemStat)) {
LOGGER.warn("ItemStat "+clazz.getName()+" 已存在"); LOGGER.warn("ItemStat "+clazz.getName()+" 已注册,将覆盖原有注册");
return; Set<Class<? extends ItemStat>> removeSet = new HashSet<>();
for (Class<? extends ItemStat> clazz1 : itemStats.keySet()) {
if (clazz1.getName().equalsIgnoreCase(itemStat.getClass().getName())) {
removeSet.add(clazz1);
}
}
removeSet.forEach((aClass -> itemStats.remove(aClass)));
} }
itemStats.put(clazz, itemStat); itemStats.put(clazz, itemStat);
} }
private static boolean isRegistered(ItemStat itemStat) {
for (Class<? extends ItemStat> clazz : itemStats.keySet()) {
if (clazz.getName().equalsIgnoreCase(itemStat.getClass().getName())) {
return true;
}
}
return itemStats.containsKey(itemStat.getClass());
}
public static void unregister(ItemStat itemStat) { public static void unregister(ItemStat itemStat) {
itemStats.remove(itemStat.getId()); itemStats.remove(itemStat.getId());
} }

View File

@ -1,6 +1,5 @@
package com.io.yutian.elementoriginlib.item.stat.type; package com.io.yutian.elementoriginlib.item.stat.type;
import com.io.yutian.elementoriginlib.exception.itemstat.ItemStatDataLoadException;
import com.io.yutian.elementoriginlib.item.TagStatItemStackBuilder; import com.io.yutian.elementoriginlib.item.TagStatItemStackBuilder;
import com.io.yutian.elementoriginlib.item.stat.ItemStat; import com.io.yutian.elementoriginlib.item.stat.ItemStat;
import com.io.yutian.elementoriginlib.item.stat.data.BooleanData; import com.io.yutian.elementoriginlib.item.stat.data.BooleanData;
@ -9,8 +8,6 @@ import com.io.yutian.elementoriginlib.tag.ItemProxy;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Objects;
public abstract class BooleanStat extends ItemStat<BooleanData> { public abstract class BooleanStat extends ItemStat<BooleanData> {
public BooleanStat(@NotNull String id, @NotNull String path) { public BooleanStat(@NotNull String id, @NotNull String path) {
@ -23,32 +20,6 @@ public abstract class BooleanStat extends ItemStat<BooleanData> {
itemProxy.editTag(tagCompound1 -> tagCompound1.putByte(getTagPath(), (byte) (statData.getValue() ? 1 : 0))); itemProxy.editTag(tagCompound1 -> tagCompound1.putByte(getTagPath(), (byte) (statData.getValue() ? 1 : 0)));
} }
@Override
public BooleanData loadAsObject(@NotNull Object value) throws ItemStatDataLoadException {
if (Objects.isNull(value)) {
throw new ItemStatDataLoadException("Invalid value: null");
}
try {
if (value instanceof Boolean bool) {
return new BooleanData(bool);
} else if (value instanceof String arg) {
boolean parsed = Boolean.parseBoolean(arg);
if (!arg.equalsIgnoreCase("true") && !arg.equalsIgnoreCase("false")) {
throw new ItemStatDataLoadException("Invalid boolean string: " + arg);
}
return new BooleanData(parsed);
} else if (value instanceof Byte b) {
return new BooleanData(b == 1);
} else if (value instanceof Integer i) {
return new BooleanData(i == 1);
} else {
throw new ItemStatDataLoadException("Invalid boolean value: " + value);
}
} catch (ClassCastException e) {
throw new ItemStatDataLoadException("Invalid type: " + value.getClass(), e);
}
}
@Nullable @Nullable
@Override @Override
public BooleanData getLoadedTag(@NotNull ItemProxy itemProxy) { public BooleanData getLoadedTag(@NotNull ItemProxy itemProxy) {

View File

@ -1,6 +1,5 @@
package com.io.yutian.elementoriginlib.item.stat.type; package com.io.yutian.elementoriginlib.item.stat.type;
import com.io.yutian.elementoriginlib.exception.itemstat.ItemStatDataLoadException;
import com.io.yutian.elementoriginlib.item.TagStatItemStackBuilder; import com.io.yutian.elementoriginlib.item.TagStatItemStackBuilder;
import com.io.yutian.elementoriginlib.item.stat.ItemStat; import com.io.yutian.elementoriginlib.item.stat.ItemStat;
import com.io.yutian.elementoriginlib.item.stat.data.DoubleListData; import com.io.yutian.elementoriginlib.item.stat.data.DoubleListData;
@ -11,9 +10,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Objects;
public abstract class DoubleListStat extends ItemStat<DoubleListData> { public abstract class DoubleListStat extends ItemStat<DoubleListData> {
@ -29,58 +26,6 @@ public abstract class DoubleListStat extends ItemStat<DoubleListData> {
itemProxy.editTag(tagCompound1 -> tagCompound1.put(getTagPath(), tagList)); itemProxy.editTag(tagCompound1 -> tagCompound1.put(getTagPath(), tagList));
} }
@Override
public DoubleListData loadAsObject(@NotNull Object value) throws ItemStatDataLoadException {
if (Objects.isNull(value)) {
throw new ItemStatDataLoadException("Invalid value: null");
}
try {
if (value instanceof List<?> list) {
List<Double> doubleList = new ArrayList<>();
for (Object item : list) {
if (item instanceof Double d) {
doubleList.add(d);
} else if (item instanceof String str) {
// 如果是 String尝试将其解析为 Double
try {
doubleList.add(Double.parseDouble(str));
} catch (NumberFormatException e) {
throw new ItemStatDataLoadException("Invalid string value for Double: " + str, e);
}
} else {
throw new ItemStatDataLoadException("List contains non-double element: " + item);
}
}
return new DoubleListData(doubleList);
} else if (value instanceof double[] array) {
List<Double> doubleList = new ArrayList<>();
for (double d : array) {
doubleList.add(d);
}
return new DoubleListData(doubleList);
} else if (value instanceof Double[] array) {
List<Double> doubleList = new ArrayList<>(Arrays.asList(array));
return new DoubleListData(doubleList);
} else if (value instanceof String str) {
List<Double> doubleList = new ArrayList<>();
String[] items = str.split(",");
for (String item : items) {
try {
doubleList.add(Double.parseDouble(item.trim()));
} catch (NumberFormatException e) {
throw new ItemStatDataLoadException("Invalid number format in string: " + item, e);
}
}
return new DoubleListData(doubleList);
} else {
throw new ItemStatDataLoadException("Invalid value type for DoubleListData: " + value);
}
} catch (Exception e) {
throw new ItemStatDataLoadException(e);
}
}
@Nullable @Nullable
@Override @Override
public DoubleListData getLoadedTag(@NotNull ItemProxy itemProxy) { public DoubleListData getLoadedTag(@NotNull ItemProxy itemProxy) {

View File

@ -1,6 +1,5 @@
package com.io.yutian.elementoriginlib.item.stat.type; package com.io.yutian.elementoriginlib.item.stat.type;
import com.io.yutian.elementoriginlib.exception.itemstat.ItemStatDataLoadException;
import com.io.yutian.elementoriginlib.item.TagStatItemStackBuilder; import com.io.yutian.elementoriginlib.item.TagStatItemStackBuilder;
import com.io.yutian.elementoriginlib.item.stat.ItemStat; import com.io.yutian.elementoriginlib.item.stat.ItemStat;
import com.io.yutian.elementoriginlib.item.stat.data.DoubleData; import com.io.yutian.elementoriginlib.item.stat.data.DoubleData;
@ -9,8 +8,6 @@ import com.io.yutian.elementoriginlib.tag.ItemProxy;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Objects;
public abstract class DoubleStat extends ItemStat<DoubleData> { public abstract class DoubleStat extends ItemStat<DoubleData> {
public DoubleStat(@NotNull String id, @NotNull String path) { public DoubleStat(@NotNull String id, @NotNull String path) {
@ -23,34 +20,6 @@ public abstract class DoubleStat extends ItemStat<DoubleData> {
itemProxy.editTag(tagCompound1 -> tagCompound1.putDouble(getTagPath(), statData.getValue())); itemProxy.editTag(tagCompound1 -> tagCompound1.putDouble(getTagPath(), statData.getValue()));
} }
@Override
public DoubleData loadAsObject(@NotNull Object value) throws ItemStatDataLoadException {
if (Objects.isNull(value)) {
throw new ItemStatDataLoadException("Invalid value: null");
}
try {
if (value instanceof Double d) {
return new DoubleData(d);
} else if (value instanceof String arg) {
try {
return new DoubleData(Double.parseDouble(arg));
} catch (NumberFormatException e) {
throw new ItemStatDataLoadException("Invalid double string: " + arg, e);
}
} else if (value instanceof Byte b) {
return new DoubleData((double) b);
} else if (value instanceof Integer i) {
return new DoubleData((double) i);
} else if (value instanceof Long l) {
return new DoubleData((double) l);
} else {
throw new ItemStatDataLoadException("Invalid double value: " + value);
}
} catch (Exception e) {
throw new ItemStatDataLoadException(e);
}
}
@Nullable @Nullable
@Override @Override
public DoubleData getLoadedTag(@NotNull ItemProxy itemProxy) { public DoubleData getLoadedTag(@NotNull ItemProxy itemProxy) {

View File

@ -1,6 +1,5 @@
package com.io.yutian.elementoriginlib.item.stat.type; package com.io.yutian.elementoriginlib.item.stat.type;
import com.io.yutian.elementoriginlib.exception.itemstat.ItemStatDataLoadException;
import com.io.yutian.elementoriginlib.item.TagStatItemStackBuilder; import com.io.yutian.elementoriginlib.item.TagStatItemStackBuilder;
import com.io.yutian.elementoriginlib.item.stat.ItemStat; import com.io.yutian.elementoriginlib.item.stat.ItemStat;
import com.io.yutian.elementoriginlib.item.stat.data.EnumListData; import com.io.yutian.elementoriginlib.item.stat.data.EnumListData;
@ -12,7 +11,6 @@ import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
public abstract class EnumListStat<E extends Enum> extends ItemStat<EnumListData<E>> { public abstract class EnumListStat<E extends Enum> extends ItemStat<EnumListData<E>> {
@ -32,55 +30,6 @@ public abstract class EnumListStat<E extends Enum> extends ItemStat<EnumListData
itemProxy.editTag(tagCompound1 -> tagCompound1.put(getTagPath(), tagList)); itemProxy.editTag(tagCompound1 -> tagCompound1.put(getTagPath(), tagList));
} }
@Override
public EnumListData<E> loadAsObject(@NotNull Object value) throws ItemStatDataLoadException {
if (Objects.isNull(value)) {
throw new ItemStatDataLoadException("Invalid value: null");
}
try {
if (value instanceof List<?> list) {
List<E> enumList = new ArrayList<>();
for (Object item : list) {
if (item instanceof String str) {
try {
E enumConstant = (E) Enum.valueOf(clazz, str);
enumList.add(enumConstant);
} catch (IllegalArgumentException e) {
throw new ItemStatDataLoadException("Invalid enum string: " + str, e);
}
} else if (item instanceof Integer i) {
E[] enumConstants = clazz.getEnumConstants();
if (i < 0 || i >= enumConstants.length) {
throw new ItemStatDataLoadException("Invalid enum ordinal: " + i);
}
enumList.add(enumConstants[i]);
} else if (item instanceof Enum<?> enumItem) {
enumList.add((E) enumItem);
} else {
throw new ItemStatDataLoadException("Invalid list element type: " + item);
}
}
return new EnumListData<>(enumList);
} else if (value instanceof String str) {
List<E> enumList = new ArrayList<>();
String[] enumNames = str.split(",");
for (String enumName : enumNames) {
try {
E enumConstant = (E) Enum.valueOf(clazz, enumName.trim());
enumList.add(enumConstant);
} catch (IllegalArgumentException e) {
throw new ItemStatDataLoadException("Invalid enum string: " + enumName, e);
}
}
return new EnumListData<>(enumList);
} else {
throw new ItemStatDataLoadException("Invalid value type for EnumListData: " + value);
}
} catch (Exception e) {
throw new ItemStatDataLoadException(e);
}
}
@Override @Override
public @Nullable EnumListData<E> getLoadedTag(@NotNull ItemProxy itemProxy) { public @Nullable EnumListData<E> getLoadedTag(@NotNull ItemProxy itemProxy) {
if (!itemProxy.has(getTagPath(), TagList.TYPE_ID)) { if (!itemProxy.has(getTagPath(), TagList.TYPE_ID)) {

View File

@ -1,6 +1,5 @@
package com.io.yutian.elementoriginlib.item.stat.type; package com.io.yutian.elementoriginlib.item.stat.type;
import com.io.yutian.elementoriginlib.exception.itemstat.ItemStatDataLoadException;
import com.io.yutian.elementoriginlib.item.TagStatItemStackBuilder; import com.io.yutian.elementoriginlib.item.TagStatItemStackBuilder;
import com.io.yutian.elementoriginlib.item.stat.ItemStat; import com.io.yutian.elementoriginlib.item.stat.ItemStat;
import com.io.yutian.elementoriginlib.item.stat.data.EnumData; import com.io.yutian.elementoriginlib.item.stat.data.EnumData;
@ -9,8 +8,6 @@ import com.io.yutian.elementoriginlib.tag.TagString;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Objects;
public abstract class EnumStat<E extends Enum> extends ItemStat<EnumData<E>> { public abstract class EnumStat<E extends Enum> extends ItemStat<EnumData<E>> {
private Class<E> clazz; private Class<E> clazz;
@ -26,35 +23,6 @@ public abstract class EnumStat<E extends Enum> extends ItemStat<EnumData<E>> {
itemProxy.editTag(tagCompound1 -> tagCompound1.putString(getTagPath(), statData.getValue().name())); itemProxy.editTag(tagCompound1 -> tagCompound1.putString(getTagPath(), statData.getValue().name()));
} }
@Override
public EnumData<E> loadAsObject(@NotNull Object value) throws ItemStatDataLoadException {
if (Objects.isNull(value)) {
throw new ItemStatDataLoadException("Invalid value: null");
}
try {
if (value instanceof Enum<?> enumValue) {
return new EnumData<>((E) enumValue);
} else if (value instanceof String str) {
try {
E enumConstant = (E) Enum.valueOf(clazz, str);
return new EnumData<>(enumConstant);
} catch (IllegalArgumentException e) {
throw new ItemStatDataLoadException("Invalid enum string: " + str, e);
}
} else if (value instanceof Integer i) {
E[] enumConstants = clazz.getEnumConstants();
if (i < 0 || i >= enumConstants.length) {
throw new ItemStatDataLoadException("Invalid enum ordinal: " + i);
}
return new EnumData<>(enumConstants[i]);
} else {
throw new ItemStatDataLoadException("Invalid value type for EnumData: " + value);
}
} catch (Exception e) {
throw new ItemStatDataLoadException(e);
}
}
@Override @Override
public @Nullable EnumData<E> getLoadedTag(@NotNull ItemProxy itemProxy) { public @Nullable EnumData<E> getLoadedTag(@NotNull ItemProxy itemProxy) {
return new EnumData(Enum.valueOf(clazz, ((TagString) itemProxy.get(getTagPath())).getString())); return new EnumData(Enum.valueOf(clazz, ((TagString) itemProxy.get(getTagPath())).getString()));

View File

@ -1,6 +1,5 @@
package com.io.yutian.elementoriginlib.item.stat.type; package com.io.yutian.elementoriginlib.item.stat.type;
import com.io.yutian.elementoriginlib.exception.itemstat.ItemStatDataLoadException;
import com.io.yutian.elementoriginlib.item.TagStatItemStackBuilder; import com.io.yutian.elementoriginlib.item.TagStatItemStackBuilder;
import com.io.yutian.elementoriginlib.item.stat.ItemStat; import com.io.yutian.elementoriginlib.item.stat.ItemStat;
import com.io.yutian.elementoriginlib.item.stat.data.IntListData; import com.io.yutian.elementoriginlib.item.stat.data.IntListData;
@ -12,7 +11,6 @@ import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
public abstract class IntListStat extends ItemStat<IntListData> { public abstract class IntListStat extends ItemStat<IntListData> {
@ -28,47 +26,6 @@ public abstract class IntListStat extends ItemStat<IntListData> {
itemProxy.editTag(tagCompound1 -> tagCompound1.put(getTagPath(), tagList)); itemProxy.editTag(tagCompound1 -> tagCompound1.put(getTagPath(), tagList));
} }
@Override
public IntListData loadAsObject(@NotNull Object value) throws ItemStatDataLoadException {
if (Objects.isNull(value)) {
throw new ItemStatDataLoadException("Invalid value: null");
}
try {
if (value instanceof List<?> list) {
List<Integer> intList = new ArrayList<>();
for (Object item : list) {
if (item instanceof Integer i) {
intList.add(i);
} else {
throw new ItemStatDataLoadException("List contains non-integer element: " + item);
}
}
return new IntListData(intList);
} else if (value instanceof int[] array) {
List<Integer> intList = new ArrayList<>();
for (int i : array) {
intList.add(i);
}
return new IntListData(intList);
} else if (value instanceof String str) {
try {
List<Integer> intList = new ArrayList<>();
String[] items = str.split(",");
for (String item : items) {
intList.add(Integer.parseInt(item.trim()));
}
return new IntListData(intList);
} catch (NumberFormatException e) {
throw new ItemStatDataLoadException("Invalid integer string: " + str, e);
}
} else {
throw new ItemStatDataLoadException("Invalid value type for IntListData: " + value);
}
} catch (Exception e) {
throw new ItemStatDataLoadException(e);
}
}
@Nullable @Nullable
@Override @Override
public IntListData getLoadedTag(@NotNull ItemProxy itemProxy) { public IntListData getLoadedTag(@NotNull ItemProxy itemProxy) {

View File

@ -1,6 +1,5 @@
package com.io.yutian.elementoriginlib.item.stat.type; package com.io.yutian.elementoriginlib.item.stat.type;
import com.io.yutian.elementoriginlib.exception.itemstat.ItemStatDataLoadException;
import com.io.yutian.elementoriginlib.item.TagStatItemStackBuilder; import com.io.yutian.elementoriginlib.item.TagStatItemStackBuilder;
import com.io.yutian.elementoriginlib.item.stat.ItemStat; import com.io.yutian.elementoriginlib.item.stat.ItemStat;
import com.io.yutian.elementoriginlib.item.stat.data.IntData; import com.io.yutian.elementoriginlib.item.stat.data.IntData;
@ -9,8 +8,6 @@ import com.io.yutian.elementoriginlib.tag.ItemProxy;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Objects;
public abstract class IntStat extends ItemStat<IntData> { public abstract class IntStat extends ItemStat<IntData> {
public IntStat(@NotNull String id, @NotNull String path) { public IntStat(@NotNull String id, @NotNull String path) {
@ -23,48 +20,6 @@ public abstract class IntStat extends ItemStat<IntData> {
itemProxy.editTag(tagCompound1 -> tagCompound1.putInt(getTagPath(), statData.getInt())); itemProxy.editTag(tagCompound1 -> tagCompound1.putInt(getTagPath(), statData.getInt()));
} }
@Override
public IntData loadAsObject(@NotNull Object value) throws ItemStatDataLoadException {
if (Objects.isNull(value)) {
throw new ItemStatDataLoadException("Invalid value: null");
}
try {
if (value instanceof Integer i) {
return new IntData(i);
} else if (value instanceof String arg) {
try {
return new IntData(Integer.parseInt(arg));
} catch (NumberFormatException e) {
throw new ItemStatDataLoadException("Invalid integer string: " + arg, e);
}
} else if (value instanceof Byte b) {
return new IntData((int) b);
} else if (value instanceof Long l) {
if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) {
throw new ItemStatDataLoadException("Long value out of range for integer: " + l);
}
return new IntData(l.intValue());
} else if (value instanceof Double d) {
if (d < Integer.MIN_VALUE || d > Integer.MAX_VALUE) {
throw new ItemStatDataLoadException("Double value out of range for integer: " + d);
}
return new IntData((int) d.doubleValue());
} else if (value instanceof Float f) {
if (f < Integer.MIN_VALUE || f > Integer.MAX_VALUE) {
throw new ItemStatDataLoadException("Float value out of range for integer: " + f);
}
return new IntData((int) f.floatValue());
} else {
throw new ItemStatDataLoadException("Invalid integer value: " + value);
}
} catch (Exception e) {
throw new ItemStatDataLoadException(e);
}
}
@Nullable @Nullable
@Override @Override
public IntData getLoadedTag(@NotNull ItemProxy itemProxy) { public IntData getLoadedTag(@NotNull ItemProxy itemProxy) {

View File

@ -1,6 +1,5 @@
package com.io.yutian.elementoriginlib.item.stat.type; package com.io.yutian.elementoriginlib.item.stat.type;
import com.io.yutian.elementoriginlib.exception.itemstat.ItemStatDataLoadException;
import com.io.yutian.elementoriginlib.item.TagStatItemStackBuilder; import com.io.yutian.elementoriginlib.item.TagStatItemStackBuilder;
import com.io.yutian.elementoriginlib.item.stat.ItemStat; import com.io.yutian.elementoriginlib.item.stat.ItemStat;
import com.io.yutian.elementoriginlib.item.stat.data.MapData; import com.io.yutian.elementoriginlib.item.stat.data.MapData;
@ -10,7 +9,6 @@ import org.jetbrains.annotations.Nullable;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects;
public class MapStat extends ItemStat<MapData> { public class MapStat extends ItemStat<MapData> {
@ -28,30 +26,6 @@ public class MapStat extends ItemStat<MapData> {
itemProxy.editTag(tagCompound1 -> tagCompound1.put(getTagPath(), tagCompound)); itemProxy.editTag(tagCompound1 -> tagCompound1.put(getTagPath(), tagCompound));
} }
@Override
public MapData loadAsObject(@NotNull Object value) throws ItemStatDataLoadException {
if (Objects.isNull(value)) {
throw new ItemStatDataLoadException("Invalid value: null");
}
try {
if (value instanceof Map<?, ?> map) {
Map<String, Object> resultMap = new HashMap<>();
for (Map.Entry<?, ?> entry : map.entrySet()) {
if (entry.getKey() instanceof String key) {
resultMap.put(key, entry.getValue());
} else {
throw new ItemStatDataLoadException("Map key is not a String: " + entry.getKey());
}
}
return new MapData(resultMap);
} else {
throw new ItemStatDataLoadException("Invalid value type for MapData: " + value);
}
} catch (Exception e) {
throw new ItemStatDataLoadException(e);
}
}
@Override @Override
public @Nullable MapData getLoadedTag(@NotNull ItemProxy itemProxy) { public @Nullable MapData getLoadedTag(@NotNull ItemProxy itemProxy) {
if (!itemProxy.has(getTagPath(), TagCompound.TYPE_ID)) { if (!itemProxy.has(getTagPath(), TagCompound.TYPE_ID)) {

View File

@ -1,6 +1,5 @@
package com.io.yutian.elementoriginlib.item.stat.type; package com.io.yutian.elementoriginlib.item.stat.type;
import com.io.yutian.elementoriginlib.exception.itemstat.ItemStatDataLoadException;
import com.io.yutian.elementoriginlib.item.TagStatItemStackBuilder; import com.io.yutian.elementoriginlib.item.TagStatItemStackBuilder;
import com.io.yutian.elementoriginlib.item.stat.ItemStat; import com.io.yutian.elementoriginlib.item.stat.ItemStat;
import com.io.yutian.elementoriginlib.item.stat.data.StringListData; import com.io.yutian.elementoriginlib.item.stat.data.StringListData;
@ -11,9 +10,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Objects;
public abstract class StringListStat extends ItemStat<StringListData> { public abstract class StringListStat extends ItemStat<StringListData> {
@ -29,38 +26,6 @@ public abstract class StringListStat extends ItemStat<StringListData> {
itemProxy.editTag(tagCompound1 -> tagCompound1.put(getTagPath(), tagList)); itemProxy.editTag(tagCompound1 -> tagCompound1.put(getTagPath(), tagList));
} }
@Override
public StringListData loadAsObject(@NotNull Object value) throws ItemStatDataLoadException {
if (Objects.isNull(value)) {
throw new ItemStatDataLoadException("Invalid value: null");
}
try {
if (value instanceof List<?> list) {
List<String> stringList = new ArrayList<>();
for (Object item : list) {
if (item instanceof String str) {
stringList.add(str);
} else {
throw new ItemStatDataLoadException("List contains non-string element: " + item);
}
}
return new StringListData(stringList);
} else if (value instanceof String[] array) {
// 处理 String[] 类型
return new StringListData(Arrays.asList(array));
} else if (value instanceof String str) {
List<String> stringList = new ArrayList<>();
stringList.add(str);
return new StringListData(stringList);
} else {
throw new ItemStatDataLoadException("Invalid value type for StringListData: " + value);
}
} catch (Exception e) {
throw new ItemStatDataLoadException(e);
}
}
@Nullable @Nullable
@Override @Override
public StringListData getLoadedTag(@NotNull ItemProxy itemProxy) { public StringListData getLoadedTag(@NotNull ItemProxy itemProxy) {

View File

@ -1,6 +1,5 @@
package com.io.yutian.elementoriginlib.item.stat.type; package com.io.yutian.elementoriginlib.item.stat.type;
import com.io.yutian.elementoriginlib.exception.itemstat.ItemStatDataLoadException;
import com.io.yutian.elementoriginlib.item.TagStatItemStackBuilder; import com.io.yutian.elementoriginlib.item.TagStatItemStackBuilder;
import com.io.yutian.elementoriginlib.item.stat.ItemStat; import com.io.yutian.elementoriginlib.item.stat.ItemStat;
import com.io.yutian.elementoriginlib.item.stat.data.StringData; import com.io.yutian.elementoriginlib.item.stat.data.StringData;
@ -9,8 +8,6 @@ import com.io.yutian.elementoriginlib.tag.TagString;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Objects;
public abstract class StringStat extends ItemStat<StringData> { public abstract class StringStat extends ItemStat<StringData> {
public StringStat(@NotNull String id, @NotNull String path) { public StringStat(@NotNull String id, @NotNull String path) {
@ -23,14 +20,6 @@ public abstract class StringStat extends ItemStat<StringData> {
itemProxy.editTag(tagCompound1 -> tagCompound1.putString(getTagPath(), statData.getString())); itemProxy.editTag(tagCompound1 -> tagCompound1.putString(getTagPath(), statData.getString()));
} }
@Override
public StringData loadAsObject(@NotNull Object value) {
if (Objects.isNull(value)) {
throw new ItemStatDataLoadException("Invalid value: null");
}
return new StringData(value.toString());
}
@Nullable @Nullable
@Override @Override
public StringData getLoadedTag(@NotNull ItemProxy itemProxy) { public StringData getLoadedTag(@NotNull ItemProxy itemProxy) {

View File

@ -1,6 +1,5 @@
package com.io.yutian.elementoriginlib.item.stat.type; package com.io.yutian.elementoriginlib.item.stat.type;
import com.io.yutian.elementoriginlib.exception.itemstat.ItemStatDataLoadException;
import com.io.yutian.elementoriginlib.item.TagStatItemStackBuilder; import com.io.yutian.elementoriginlib.item.TagStatItemStackBuilder;
import com.io.yutian.elementoriginlib.item.stat.ItemStat; import com.io.yutian.elementoriginlib.item.stat.ItemStat;
import com.io.yutian.elementoriginlib.item.stat.data.UUIDData; import com.io.yutian.elementoriginlib.item.stat.data.UUIDData;
@ -9,7 +8,6 @@ import com.io.yutian.elementoriginlib.tag.TagString;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.UUID; import java.util.UUID;
public abstract class UUIDStat extends ItemStat<UUIDData> { public abstract class UUIDStat extends ItemStat<UUIDData> {
@ -24,28 +22,6 @@ public abstract class UUIDStat extends ItemStat<UUIDData> {
itemProxy.editTag(tagCompound1 -> tagCompound1.putString(getTagPath(), statData.getUUID().toString())); itemProxy.editTag(tagCompound1 -> tagCompound1.putString(getTagPath(), statData.getUUID().toString()));
} }
@Override
public UUIDData loadAsObject(@NotNull Object value) throws ItemStatDataLoadException {
if (Objects.isNull(value)) {
throw new ItemStatDataLoadException("Invalid value: null");
}
try {
if (value instanceof UUID uuid) {
return new UUIDData(uuid);
} else if (value instanceof String str) {
try {
return new UUIDData(UUID.fromString(str));
} catch (IllegalArgumentException e) {
throw new ItemStatDataLoadException("Invalid UUID string: " + str, e);
}
} else {
throw new ItemStatDataLoadException("Invalid UUID value: " + value);
}
} catch (Exception e) {
throw new ItemStatDataLoadException(e);
}
}
@Nullable @Nullable
@Override @Override
public UUIDData getLoadedTag(@NotNull ItemProxy itemProxy) { public UUIDData getLoadedTag(@NotNull ItemProxy itemProxy) {

View File

@ -15,10 +15,12 @@ public class Lang {
private static Map<String, String> langMap = new HashMap<>(); private static Map<String, String> langMap = new HashMap<>();
public static String get(String key) { public static String get(String key) {
key = key.toLowerCase();
return langMap.getOrDefault(key, "§o"+key); return langMap.getOrDefault(key, "§o"+key);
} }
public static String get(String key, Object... args) { public static String get(String key, Object... args) {
key = key.toLowerCase();
String s = langMap.getOrDefault(key, "§o"+key); String s = langMap.getOrDefault(key, "§o"+key);
for (int i = 0; i < args.length; i++) { for (int i = 0; i < args.length; i++) {
s = s.replace("$"+i, String.valueOf(args[i])); s = s.replace("$"+i, String.valueOf(args[i]));
@ -27,6 +29,7 @@ public class Lang {
} }
public static Optional<String> getOptional(String key) { public static Optional<String> getOptional(String key) {
key = key.toLowerCase();
return Optional.ofNullable(langMap.get(key)); return Optional.ofNullable(langMap.get(key));
} }

View File

@ -0,0 +1,14 @@
package com.io.yutian.elementoriginlib.mongodb;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Collection {
String value() default "";
}

View File

@ -0,0 +1,9 @@
package com.io.yutian.elementoriginlib.mongodb;
import java.util.UUID;
public interface MongoEntity {
UUID getUUID();
}

View File

@ -0,0 +1,722 @@
package com.io.yutian.elementoriginlib.mongodb;
import com.io.yutian.elementoriginlib.serialize.SerializeHelper;
import com.mongodb.BasicDBObject;
import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.client.*;
import com.mongodb.client.model.Filters;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import org.bson.Document;
import org.bson.UuidRepresentation;
import org.bson.codecs.UuidCodec;
import org.bson.codecs.configuration.CodecRegistries;
import org.bson.codecs.configuration.CodecRegistry;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class MongoSupport {
private final static Logger LOG = LoggerFactory.getLogger(MongoSupport.class);
public final static String ID = "_id";
private final static Map<Class<?>, String> classCollectionName = new ConcurrentHashMap<>();
private final static Map<String, MongoCollection<Document>> collections = new ConcurrentHashMap<>();
private static final CodecRegistry CODEC_REGISTRY = CodecRegistries.fromRegistries(
CodecRegistries.fromCodecs(new UuidCodec(UuidRepresentation.STANDARD)),
MongoClientSettings.getDefaultCodecRegistry()
);
protected MongoDatabase mongoDatabase;
public MongoSupport(String host, int port, String username, String password, String dbname) {
String connectionString = String.format(
"mongodb://%s:%s@%s:%d/?authSource=admin",
URLEncoder.encode(username, StandardCharsets.UTF_8),
URLEncoder.encode(password, StandardCharsets.UTF_8),
host, port
);
MongoClientSettings settings = MongoClientSettings.builder()
.applyConnectionString(new ConnectionString(connectionString))
.codecRegistry(CODEC_REGISTRY)
.uuidRepresentation(UuidRepresentation.STANDARD)
.build();
MongoClient client = MongoClients.create(settings);
mongoDatabase = client.getDatabase(dbname);
if (mongoDatabase == null) {
throw new IllegalArgumentException("获取数据库实例失败:" + dbname);
}
}
public MongoSupport(MongoClient mongo, String dbname) {
mongoDatabase = mongo.getDatabase(dbname);
if (mongoDatabase == null) {
throw new IllegalArgumentException("获取数据库实例失败:" + dbname);
}
}
public MongoDatabase getMongoDatabase() {
return mongoDatabase;
}
public List<String> getCollectionNames() {
List<String> list = new ArrayList<>();
MongoCursor<String> cursor = mongoDatabase.listCollectionNames().iterator();
while (cursor.hasNext()) {
list.add(cursor.next());
}
cursor.close();
return list;
}
public MongoCollection<Document> getCollection(String collectionName) {
MongoCollection<Document> coll = collections.get(collectionName);
if (coll == null) {
coll = mongoDatabase.getCollection(collectionName);
collections.put(collectionName, coll);
}
return coll;
}
public List<Document> findAll(String collectionName) {
return find(collectionName, null, null, 0, 0);
}
public List<Document> findAll(String collectionName, Bson orderBy) {
return find(collectionName, null, orderBy, 0, 0);
}
public List<Document> findAll(String collectionName, Bson orderBy, int limit) {
return find(collectionName, null, orderBy, limit, 0);
}
public List<Document> findAll(String collectionName, int limit) {
return find(collectionName, null, null, limit, 0);
}
public List<Document> findAll(String collectionName, int limit, int skip) {
return find(collectionName, null, null, limit, skip);
}
public List<Document> findAll(String collectionName, Bson orderBy, int limit, int skip) {
return find(collectionName, null, orderBy, limit, skip);
}
private <T> String getCollectionName(Class<T> clazz) {
if (classCollectionName.containsKey(clazz)) {
return classCollectionName.get(clazz);
}
String collectionName = clazz.getSimpleName();
Collection collection = clazz.getAnnotation(Collection.class);
if (collection != null && collection.value() != null && !collection.value().isEmpty()) {
collectionName = collection.value();
}
return classCollectionName.put(clazz, collectionName);
}
public <T> List<T> findAll(Class<T> clazz) {
String collectionName = getCollectionName(clazz);
return find(clazz, collectionName, null, null, 0, 0);
}
public <T> List<T> findAll(Class<T> clazz, String collectionName) {
return find(clazz, collectionName, null, null, 0, 0);
}
public <T> List<T> findAll(Class<T> clazz, String collectionName, Bson orderBy) {
return find(clazz, collectionName, null, orderBy, 0, 0);
}
public <T> List<T> findAll(Class<T> clazz, String collectionName, Bson orderBy, int limit) {
return find(clazz, collectionName, null, orderBy, limit, 0);
}
public <T> List<T> findAll(Class<T> clazz, String collectionName, int limit) {
return find(clazz, collectionName, null, null, limit, 0);
}
public <T> List<T> findAll(Class<T> clazz, String collectionName, int limit, int skip) {
return find(clazz, collectionName, null, null, limit, skip);
}
public <T> List<T> findAll(Class<T> clazz, String collectionName, Bson orderBy, int limit, int skip) {
return find(clazz, collectionName, null, orderBy, limit, skip);
}
public List<Document> find(String collectionName, Bson filter) {
return find(collectionName, filter, null, 0, 0);
}
public List<Document> find(String collectionName, Bson filter, Bson orderBy) {
return find(collectionName, filter, orderBy, 0, 0);
}
public List<Document> find(String collectionName, Bson filter, Bson orderBy, int limit) {
return find(collectionName, filter, orderBy, 0, 0);
}
public List<Document> find(String collectionName, Bson filter, int limit) {
return find(collectionName, filter, null, 0, 0);
}
public List<Document> find(String collectionName, Bson filter, int limit, int skip) {
return find(collectionName, filter, null, 0, 0);
}
public List<Document> find(String collectionName, Bson filter, Bson orderBy, int limit, int skip) {
FindIterable<Document> find = null;
if (filter == null) {
find = getCollection(collectionName).find();
} else {
find = getCollection(collectionName).find(filter);
}
if (orderBy != null) {
find.sort(orderBy);
}
if (skip > 0) {
find.skip(skip);
}
if (limit > 0) {
find.limit(limit);
}
MongoCursor<Document> cursor = find.iterator();
List<Document> list = new ArrayList<>();
try {
while (cursor.hasNext()) {
list.add(cursor.next());
}
} finally {
cursor.close();
}
return list;
}
public <T> List<T> find(Class<T> clazz, Bson filter) {
String collectionName = getCollectionName(clazz);
return find(clazz, collectionName, filter, null, 0, 0);
}
public <T> List<T> find(Class<T> clazz, Bson filter, Bson orderBy) {
String collectionName = getCollectionName(clazz);
return find(clazz, collectionName, filter, orderBy, 0, 0);
}
public <T> List<T> find(Class<T> clazz, Bson filter, Bson orderBy, int limit) {
String collectionName = getCollectionName(clazz);
return find(clazz, collectionName, filter, orderBy, limit, 0);
}
public <T> List<T> find(Class<T> clazz, Bson filter, int limit) {
String collectionName = getCollectionName(clazz);
return find(clazz, collectionName, filter, null, limit, 0);
}
public <T> List<T> find(Class<T> clazz, Bson filter, int limit, int skip) {
String collectionName = getCollectionName(clazz);
return find(clazz, collectionName, filter, null, limit, skip);
}
public <T> List<T> find(Class<T> clazz, String collectionName, Bson filter) {
return find(clazz, collectionName, filter, null, 0, 0);
}
public <T> List<T> find(Class<T> clazz, String collectionName, Bson filter, Bson orderBy) {
return find(clazz, collectionName, filter, orderBy, 0, 0);
}
public <T> List<T> find(Class<T> clazz, String collectionName, Bson filter, Bson orderBy, int limit) {
return find(clazz, collectionName, filter, orderBy, limit, 0);
}
public <T> List<T> find(Class<T> clazz, String collectionName, Bson filter, int limit) {
return find(clazz, collectionName, filter, null, limit, 0);
}
public <T> List<T> find(Class<T> clazz, String collectionName, Bson filter, int limit, int skip) {
return find(clazz, collectionName, filter, null, limit, skip);
}
public <T> List<T> find(Class<T> clazz, String collectionName, Bson filter, Bson orderBy, int limit, int skip) {
FindIterable<Document> find = null;
if (filter == null) {
find = getCollection(collectionName).find();
} else {
find = getCollection(collectionName).find(filter);
}
if (orderBy != null) {
find.sort(orderBy);
}
if (skip > 0) {
find.skip(skip);
}
if (limit > 0) {
find.limit(limit);
}
MongoCursor<Document> cursor = find.iterator();
List<T> list = new ArrayList<T>();
try {
while (cursor.hasNext()) {
Document doc = cursor.next();
ObjectId id = doc.getObjectId(ID);
if (id != null) {
doc.put(ID, id.toHexString());
}
String json = doc.toJson();
list.add(SerializeHelper.deserialize(json, clazz));
}
} finally {
cursor.close();
}
return list;
}
public List<Document> distinct(String collectionName, String fieldName, Bson filter) {
DistinctIterable<Document> find = null;
if (filter == null) {
find = getCollection(collectionName).distinct(fieldName, Document.class);
} else {
find = getCollection(collectionName).distinct(fieldName, filter, Document.class);
}
MongoCursor<Document> cursor = find.iterator();
List<Document> list = new ArrayList<>();
try {
while (cursor.hasNext()) {
list.add(cursor.next());
}
} finally {
cursor.close();
}
return list;
}
public Document findOne(String collectionName, Bson filter) {
MongoCursor<Document> cursor = getCollection(collectionName).find(filter).iterator();
try {
if (cursor.hasNext()) {
return cursor.next();
}
} finally {
cursor.close();
}
return null;
}
public <T> T findOne(Class<T> clazz, Bson filter) {
String collectionName = getCollectionName(clazz);
return findOne(clazz, collectionName, filter);
}
public <T> T findOne(Class<T> clazz, String collectionName, Bson filter) {
MongoCursor<Document> cursor = getCollection(collectionName).find(filter).iterator();
try {
if (cursor.hasNext()) {
Document doc = cursor.next();
ObjectId id = doc.getObjectId(ID);
if (id != null) {
doc.put(ID, id.toHexString());
}
String json = doc.toJson();
return SerializeHelper.deserialize(json, clazz);
}
} finally {
cursor.close();
}
return null;
}
public <T> T findById(Class<T> clazz, UUID id) {
String collectionName = getCollectionName(clazz);
return findById(clazz, collectionName, id);
}
public <T> T findById(Class<T> clazz, String collectionName, UUID id) {
Bson filter = Filters.eq(ID, id);
MongoCursor<Document> cursor = getCollection(collectionName).find(filter).iterator();
try {
if (cursor.hasNext()) {
Document doc = cursor.next();
ObjectId _id = doc.getObjectId(ID);
if (_id != null) {
doc.put(ID, _id.toHexString());
}
String json = doc.toJson();
return SerializeHelper.deserialize(json, clazz);
}
} finally {
cursor.close();
}
return null;
}
public Document findById(String collectionName, UUID id) {
Bson filter = Filters.eq(ID, id);
MongoCursor<Document> cursor = getCollection(collectionName).find(filter).iterator();
try {
if (cursor.hasNext()) {
return cursor.next();
}
} finally {
cursor.close();
}
return null;
}
public <T> long count(Class<T> clazz) {
String collectionName = getCollectionName(clazz);
return count(collectionName);
}
public long count(String collectionName) {
return getCollection(collectionName).countDocuments();
}
public <T> long count(Class<T> clazz, Bson filter) {
String collectionName = getCollectionName(clazz);
return count(collectionName, filter);
}
public long count(String collectionName, Bson filter) {
if (filter == null) {
return getCollection(collectionName).countDocuments();
}
return getCollection(collectionName).countDocuments(filter);
}
public List<Document> count(String collectionName, String[] groupBy) {
return count(collectionName, groupBy, null, 0);
}
public List<Document> count(String collectionName, String[] groupBy, Bson filter) {
return count(collectionName, groupBy, filter, 0);
}
public List<Document> count(String collectionName, String[] groupBy, Bson filter, int limit) {
StringBuilder mapFunction = new StringBuilder("function(){emit(");
int len = groupBy.length;
if (len == 1) {
mapFunction.append("this.").append(groupBy[0]);
} else {
mapFunction.append("{");
for (int i = 0; i < len; i++) {
if (i > 0) {
mapFunction.append(",");
}
mapFunction.append(groupBy[i]).append(":this.").append(groupBy[i]);
}
mapFunction.append("}");
}
mapFunction.append(",1");
mapFunction.append(");}");
StringBuilder reduceFunction = new StringBuilder("function(key, values){");
reduceFunction.append("var total = 0;");
reduceFunction.append("values.forEach(function(val){total += val;});");
reduceFunction.append("return total;");
reduceFunction.append("}");
MapReduceIterable<Document> find = getCollection(collectionName).mapReduce(mapFunction.toString(), reduceFunction.toString());
if (filter != null) {
find.filter(filter);
}
if (limit > 0) {
find.limit(limit);
}
find.jsMode(true);
MongoCursor<Document> cursor = find.iterator();
List<Document> list = new ArrayList<Document>();
try {
while (cursor.hasNext()) {
Document doc = cursor.next();
if (len == 1) {
doc.put(groupBy[0], doc.get("_id"));
} else {
doc.putAll((Document) doc.get("_id"));
}
doc.remove("_id");
Object val = doc.get("value");
if (val instanceof List) {
val = ((List) val).get(0);
}
long count = 0;
if (val instanceof Number) {
count = ((Number)val).longValue();
} else {
LOG.warn("{} is not a number!!! doc={}", val, doc);
}
doc.remove("value");
doc.put("count", count);
list.add(doc);
}
} finally {
cursor.close();
}
return list;
}
public List<Document> mapReduce(String collectionName, String mapFunction, String reduceFunction) {
return mapReduce(collectionName, mapFunction, reduceFunction, null, null, null, 0);
}
public List<Document> mapReduce(String collectionName, String mapFunction, String reduceFunction, Bson filter) {
return mapReduce(collectionName, mapFunction, reduceFunction, null, filter, null, 0);
}
public List<Document> mapReduce(String collectionName, String mapFunction, String reduceFunction, Bson filter, Bson orderBy) {
return mapReduce(collectionName, mapFunction, reduceFunction, null, filter, orderBy, 0);
}
public List<Document> mapReduce(String collectionName, String mapFunction, String reduceFunction, Bson filter, int limit) {
return mapReduce(collectionName, mapFunction, reduceFunction, null, filter, null, limit);
}
public List<Document> mapReduce(String collectionName, String mapFunction, String reduceFunction, String finalizeFunction) {
return mapReduce(collectionName, mapFunction, reduceFunction, finalizeFunction, null, null, 0);
}
public List<Document> mapReduce(String collectionName, String mapFunction, String reduceFunction, String finalizeFunction, Bson filter) {
return mapReduce(collectionName, mapFunction, reduceFunction, finalizeFunction, filter, null, 0);
}
public List<Document> mapReduce(String collectionName, String mapFunction, String reduceFunction, String finalizeFunction, Bson filter, Bson orderBy) {
return mapReduce(collectionName, mapFunction, reduceFunction, finalizeFunction, filter, orderBy, 0);
}
public List<Document> mapReduce(String collectionName, String mapFunction, String reduceFunction, String finalizeFunction, Bson filter, int limit) {
return mapReduce(Document.class, collectionName, mapFunction, reduceFunction, finalizeFunction, filter, null, limit);
}
public List<Document> mapReduce(String collectionName, String mapFunction, String reduceFunction, String finalizeFunction, Bson filter, Bson orderBy, int
limit) {
return mapReduce(Document.class, collectionName, mapFunction, reduceFunction, finalizeFunction, filter, orderBy, limit);
}
public <T> List<T> mapReduce(Class<T> resultClass, String collectionName, String mapFunction, String reduceFunction, String finalizeFunction, Bson
filter, int limit) {
return mapReduce(resultClass, collectionName, mapFunction, reduceFunction, finalizeFunction, filter, null, limit);
}
public <T> List<T> mapReduce(Class<T> resultClass, String collectionName, String mapFunction, String reduceFunction, String finalizeFunction, Bson
filter, Bson orderBy, int limit) {
MapReduceIterable<T> find = getCollection(collectionName).mapReduce(mapFunction, reduceFunction, resultClass);
if (filter != null) {
find.filter(filter);
}
if (finalizeFunction != null && !finalizeFunction.isEmpty()) {
find.finalizeFunction(finalizeFunction);
}
if (orderBy != null) {
find.sort(orderBy);
}
if (limit > 0) {
find.limit(limit);
}
find.jsMode(true);
MongoCursor<T> cursor = find.iterator();
List<T> list = new ArrayList<T>();
try {
while (cursor.hasNext()) {
list.add(cursor.next());
}
} finally {
cursor.close();
}
return list;
}
public void save(Object entity) {
Class<?> clazz = entity.getClass();
String collectionName = getCollectionName(clazz);
save(entity, collectionName);
}
public void save(Object entity, String collectionName) {
if (entity instanceof Document) {
getCollection(collectionName).insertOne((Document) entity);
} else if (entity instanceof Map) {
getCollection(collectionName).insertOne(new Document((Map<String, Object>) entity));
} else {
String json = toJson(entity);
getCollection(collectionName).insertOne(Document.parse(json));
}
}
public void saveAll(List<?> list) {
Class<?> clazz = list.get(0).getClass();
String collectionName = getCollectionName(clazz);
saveAll(list, collectionName);
}
public void saveAll(List<?> list, String collectionName) {
List<Document> docList = new ArrayList<>();
for (Object obj : list) {
if (obj instanceof Document) {
docList.add((Document) obj);
} else if (obj instanceof Map) {
docList.add(new Document((Map<String, Object>) obj));
} else {
String json = toJson(obj);
docList.add(Document.parse(json));
}
}
getCollection(collectionName).insertMany(docList);
}
public <T> boolean update(T entity) {
String collectionName = getCollectionName(entity.getClass());
return update(entity, collectionName);
}
public <T> boolean update(T entity, String collectionName) {
UUID id = null;
if (entity instanceof MongoEntity mongoEntity) {
}
return updateById(entity, collectionName, id);
}
public <T> long update(T entity, Bson filter) {
String collectionName = getCollectionName(entity.getClass());
return update(entity, collectionName, filter, false);
}
public <T> long update(T entity, Bson filter, boolean mutil) {
String collectionName = getCollectionName(entity.getClass());
return update(entity, collectionName, filter, mutil);
}
public <T> long update(T entity, String collectionName, Bson filter, boolean mutil) {
String json = toJson(entity);
BasicDBObject update = BasicDBObject.parse(json);
return update(collectionName, filter, new BasicDBObject("$set", update), mutil);
}
public long update(String collectionName, Bson filter, UpdateEntity updateEntity) {
return update(collectionName, filter, updateEntity, false);
}
public long update(String collectionName, Bson filter, UpdateEntity updateEntity, boolean mutil) {
BasicDBObject _update = new BasicDBObject();
if (!updateEntity.inc().isEmpty()) {
_update.append("$inc", updateEntity.inc());
}
if (!updateEntity.set().isEmpty()) {
_update.append("$set", updateEntity.set());
}
if (!updateEntity.unset().isEmpty()) {
_update.append("$unset", updateEntity.unset());
}
return update(collectionName, filter, _update, mutil);
}
public long update(String collectionName, Bson filter, Bson update, boolean mutil) {
UpdateResult result = null;
if (mutil) {
result = getCollection(collectionName).updateMany(filter, update);
} else {
result = getCollection(collectionName).updateOne(filter, update);
}
if (result.wasAcknowledged()) {
return result.getModifiedCount();
}
return -1;
}
public <T> boolean updateById(T entity, UUID id) {
String collectionName = getCollectionName(entity.getClass());
return updateById(entity, collectionName, id);
}
public <T> boolean updateById(T entity, String collectionName, UUID id) {
if (id == null) {
throw new IllegalArgumentException("id不能为空");
}
String json = toJson(entity);
Bson filter = Filters.eq(ID, id);
BasicDBObject update = BasicDBObject.parse(json);
UpdateResult result = getCollection(collectionName).updateOne(filter, new BasicDBObject("$set", update));
if (result.wasAcknowledged()) {
if (result.getModifiedCount() > 0) {
return true;
}
} else {
return true;
}
return false;
}
public boolean updateById(String collectionName, UpdateEntity updateEntity, UUID id) {
BasicDBObject _update = new BasicDBObject();
if (!updateEntity.inc().isEmpty()) {
_update.append("$inc", updateEntity.inc());
}
if (!updateEntity.set().isEmpty()) {
_update.append("$set", updateEntity.set());
}
if (!updateEntity.unset().isEmpty()) {
_update.append("$unset", updateEntity.unset());
}
return updateById(collectionName, _update, id);
}
public boolean updateById(String collectionName, Bson update, UUID id) {
if (id == null) {
throw new IllegalArgumentException("id不能为空");
}
Bson filter = Filters.eq(ID, id);
UpdateResult result = getCollection(collectionName).updateOne(filter, update);
if (result.wasAcknowledged()) {
return (result.getModifiedCount() > 0);
}
return true;
}
public boolean deleteOne(String collectionName, Bson filter) {
DeleteResult result = getCollection(collectionName).deleteOne(filter);
if (result.wasAcknowledged()) {
return (result.getDeletedCount() > 0);
}
return true;
}
public long deleteAll(String collectionName, Bson filter) {
DeleteResult result = getCollection(collectionName).deleteMany(filter);
if (result.wasAcknowledged()) {
return result.getDeletedCount();
}
return 0;
}
public boolean deleteById(String collectionName, UUID id) {
return deleteOne(collectionName, Filters.eq(ID, id));
}
public void drop(String collectionName) {
getCollection(collectionName).drop();
}
public void createIndex(String collectionName, Bson keys) {
getCollection(collectionName).createIndex(keys);
}
public void dropIndexes(String collectionName) {
getCollection(collectionName).dropIndexes();
}
public void dropIndex(String collectionName, String indexName) {
getCollection(collectionName).dropIndex(indexName);
}
protected String toJson(Object obj) {
return SerializeHelper.serialize(obj);
}
}

View File

@ -0,0 +1,49 @@
package com.io.yutian.elementoriginlib.mongodb;
import com.mongodb.BasicDBObject;
public class UpdateEntity {
private BasicDBObject incObjects = new BasicDBObject();
private BasicDBObject setObjects = new BasicDBObject();
private BasicDBObject unsetObjects = new BasicDBObject();
public UpdateEntity() {
}
public UpdateEntity(BasicDBObject set) {
this.setObjects = set;
}
public UpdateEntity set(String key, Object value) {
setObjects.append(key, value);
return this;
}
public UpdateEntity unset(String key) {
unsetObjects.append(key, 0);
return this;
}
public UpdateEntity inc(String key, int value) {
incObjects.append(key, value);
return this;
}
public BasicDBObject set() {
return setObjects;
}
public BasicDBObject unset() {
return unsetObjects;
}
public BasicDBObject inc() {
return incObjects;
}
public void reset() {
setObjects.clear();
incObjects.clear();
unsetObjects.clear();
}
}

View File

@ -4,6 +4,9 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.util.NumberConversions;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import java.util.Objects; import java.util.Objects;
@ -61,6 +64,23 @@ public class Point {
this.z = z; this.z = z;
} }
public double distance(@NotNull Point o) {
return Math.sqrt(this.distanceSquared(o));
}
public double distance(@NotNull Vector o) {
return Math.sqrt(this.distanceSquared(o));
}
public double distanceSquared(@NotNull Point o) {
return NumberConversions.square(this.x - o.x) + NumberConversions.square(this.y - o.y) + NumberConversions.square(this.z - o.z);
}
public double distanceSquared(@NotNull Vector o) {
return NumberConversions.square(this.x - o.getX()) + NumberConversions.square(this.y - o.getY()) + NumberConversions.square(this.z - o.getZ());
}
public Point clone() { public Point clone() {
return new Point(x, y, z); return new Point(x, y, z);
} }

View File

@ -1,6 +1,5 @@
package com.io.yutian.elementoriginlib.point; package com.io.yutian.elementoriginlib.point;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World; import org.bukkit.World;
@ -30,6 +29,13 @@ public class Region {
return max; return max;
} }
public Point getCenter() {
double centerX = (min.getX() + max.getX()) / 2.0;
double centerY = (min.getY() + max.getY()) / 2.0;
double centerZ = (min.getZ() + max.getZ()) / 2.0;
return new Point(centerX, centerY, centerZ);
}
public static Region deserialize(ConfigurationSection section) { public static Region deserialize(ConfigurationSection section) {
World world1 = Bukkit.getWorld(section.getString("world")); World world1 = Bukkit.getWorld(section.getString("world"));
Point point1 = Point.deserialize(section.getConfigurationSection("min")); Point point1 = Point.deserialize(section.getConfigurationSection("min"));

View File

@ -0,0 +1,9 @@
package com.io.yutian.elementoriginlib.scanner;
public interface ClassLoaderProcessor {
boolean isMatch(Class loaderClass, byte[] classBytes);
void process(Class loaderClass, Object instance);
}

View File

@ -0,0 +1,317 @@
package com.io.yutian.elementoriginlib.scanner;
import com.io.yutian.elementoriginlib.logger.Logger;
import com.io.yutian.elementoriginlib.shadowloader.BytecodeRewriter;
import com.io.yutian.elementoriginlib.shadowloader.ShadowClassLoader;
import javassist.ClassPool;
import javassist.CtClass;
import java.io.*;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class ClassScanner {
private static final Logger LOGGER = Logger.getLogger(ClassScanner.class);
private static final int THREAD_COUNT = Runtime.getRuntime().availableProcessors();
public static final Set<String> DEFAULT_PACKAGES = new HashSet<>(Arrays.asList("com.io.yutian"));
public static final Set<String> DEFAULT_EXCLUDE_PACKAGES = new HashSet<>(Arrays.asList("com.io.yutian.elementoriginlib"));
private Set<String> packageNames;
private Set<String> excludePackageNames;
private ClassLoaderProcessor classLoaderProcessor;
private ClassLoader classLoader;
private Set<Class<?>> scannedClasses = ConcurrentHashMap.newKeySet();
private Map<String, Object> scannedClassInstances = new ConcurrentHashMap<>();
public ClassScanner(Set<String> packageNames, Set<String> excludePackageNames, ClassLoader classLoader, ClassLoaderProcessor classLoaderProcessor) {
this.packageNames = packageNames;
this.excludePackageNames = excludePackageNames;
this.classLoader = classLoader;
this.classLoaderProcessor = classLoaderProcessor;
}
public void scan(File pluginsFolder) {
File[] jars = pluginsFolder.listFiles((dir, name) -> name.endsWith(".jar"));
if (jars == null) return;
ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT);
for (File jar : jars) {
executor.submit(() -> {
try {
scanJar(jar);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
});
}
executor.shutdown();
try {
executor.awaitTermination(60, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
private void scanJar(File jarFile) throws IOException {
try (JarFile jar = new JarFile(jarFile)) {
Enumeration<JarEntry> entries = jar.entries();
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{jarFile.toURI().toURL()}, classLoader);
ShadowClassLoader shadowLoader = new ShadowClassLoader(classLoader);
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (entry.getName().endsWith(".class")) {
String className = entry.getName().replace("/", ".").replace(".class", "");
if (excludePackageNames.stream().anyMatch(className::startsWith)) {
continue;
}
if (packageNames.stream().noneMatch(className::startsWith)) {
continue;
}
try (InputStream is = jar.getInputStream(entry)) {
byte[] originalBytes = is.readAllBytes();
Class<?> clazz = urlClassLoader.loadClass(className);
if (classLoaderProcessor.isMatch(clazz, originalBytes)) {
String newName = "lib.shadow." + clazz.getName();
byte[] newBytes = BytecodeRewriter.rewriteClass(originalBytes, className, newName);
Class<?> newClass = shadowLoader.define(newName, newBytes);
Object instance = newClass.newInstance();
classLoaderProcessor.process(newClass, instance);
scannedClasses.add(clazz);
scannedClassInstances.put(clazz.getName(), instance);
}
} catch (Throwable ignored) {
LOGGER.error(ignored.getMessage(), ignored);
}
}
}
}
}
public static Map<String, Map<String, Object>> getClassAnnotations(byte[] classBytes) {
Map<String, Map<String, Object>> annotations = new HashMap<>();
try (DataInputStream in = new DataInputStream(new ByteArrayInputStream(classBytes))) {
in.skipBytes(8); // magic, minor, major
int cpCount = in.readUnsignedShort();
Map<Integer, String> utf8 = new HashMap<>();
Map<Integer, Integer> classInfo = new HashMap<>();
for (int i = 1; i < cpCount; i++) {
int tag = in.readUnsignedByte();
switch (tag) {
case 1 -> utf8.put(i, in.readUTF());
case 3, 4 -> in.skipBytes(4);
case 5, 6 -> { in.skipBytes(8); i++; }
case 7 -> classInfo.put(i, in.readUnsignedShort());
case 8 -> in.readUnsignedShort();
case 9, 10, 11, 12, 18 -> in.skipBytes(4);
case 15 -> in.skipBytes(3);
case 16 -> in.skipBytes(2);
case 17 -> in.skipBytes(4);
default -> throw new IOException("Bad constant pool tag: " + tag);
}
}
in.skipBytes(2 + 2 + 2); // access_flags, this_class, super_class
int interfacesCount = in.readUnsignedShort();
in.skipBytes(2 * interfacesCount);
int fieldsCount = in.readUnsignedShort();
skipAttributes(in, fieldsCount);
int methodsCount = in.readUnsignedShort();
skipAttributes(in, methodsCount);
int attributesCount = in.readUnsignedShort();
for (int i = 0; i < attributesCount; i++) {
int nameIndex = in.readUnsignedShort();
String attrName = utf8.get(nameIndex);
int length = in.readInt();
if ("RuntimeVisibleAnnotations".equals(attrName)) {
int numAnnotations = in.readUnsignedShort();
for (int j = 0; j < numAnnotations; j++) {
int typeIndex = in.readUnsignedShort();
String desc = utf8.get(typeIndex);
if (desc == null) continue;
String annotationClass = desc.substring(1, desc.length() - 1).replace("/", ".");
Map<String, Object> values = readAnnotationValues(in, utf8);
annotations.put(annotationClass, values);
}
} else {
in.skipBytes(length);
}
}
} catch (IOException ignored) {
}
return annotations;
}
private static void skipAttributes(DataInputStream in, int count) throws IOException {
for (int i = 0; i < count; i++) {
in.skipBytes(6); // access_flags, name_index, descriptor_index
int attributesCount = in.readUnsignedShort();
for (int j = 0; j < attributesCount; j++) {
in.skipBytes(2); // attribute_name_index
int length = in.readInt();
in.skipBytes(length);
}
}
}
private static Map<String, Object> readAnnotationValues(DataInputStream in, Map<Integer, String> utf8) throws IOException {
Map<String, Object> map = new HashMap<>();
int numPairs = in.readUnsignedShort();
for (int i = 0; i < numPairs; i++) {
int elementNameIndex = in.readUnsignedShort();
String elementName = utf8.get(elementNameIndex);
Object value = readElementValue(in, utf8);
map.put(elementName, value);
}
return map;
}
private static Object readElementValue(DataInputStream in, Map<Integer, String> utf8) throws IOException {
char tag = (char) in.readUnsignedByte();
return switch (tag) {
case 'B', 'C', 'D', 'F', 'I', 'J', 'S', 'Z', 's' -> {
int constIndex = in.readUnsignedShort();
yield utf8.get(constIndex);
}
case 'e' -> {
in.skipBytes(4);
yield "<Enum>";
}
case 'c' -> {
in.skipBytes(2);
yield "<Class>";
}
case '@' -> {
skipAnnotation(in, utf8);
yield "<Annotation>";
}
case '[' -> {
int numValues = in.readUnsignedShort();
List<Object> list = new ArrayList<>();
for (int i = 0; i < numValues; i++) {
list.add(readElementValue(in, utf8));
}
yield list;
}
default -> null;
};
}
private static void skipAnnotation(DataInputStream in, Map<Integer, String> utf8) throws IOException {
in.skipBytes(2);
int numPairs = in.readUnsignedShort();
for (int i = 0; i < numPairs; i++) {
in.skipBytes(2);
readElementValue(in, utf8);
}
}
public static String getSuperClassName(byte[] classBytes) {
try (DataInputStream in = new DataInputStream(new ByteArrayInputStream(classBytes))) {
in.skipBytes(8); // magic + minor + major
int constantPoolCount = in.readUnsignedShort();
Map<Integer, String> utf8Constants = new HashMap<>();
Map<Integer, Integer> classInfo = new HashMap<>();
for (int i = 1; i < constantPoolCount; i++) {
int tag = in.readUnsignedByte();
switch (tag) {
case 1 -> utf8Constants.put(i, in.readUTF()); // Utf8
case 3, 4 -> in.skipBytes(4);
case 5, 6 -> { in.skipBytes(8); i++; }
case 7 -> classInfo.put(i, in.readUnsignedShort());
case 8 -> in.readUnsignedShort();
case 9, 10, 11, 12, 18 -> in.skipBytes(4);
case 15 -> in.skipBytes(3);
case 16 -> in.skipBytes(2);
case 17 -> in.skipBytes(4);
default -> throw new IOException("Bad constant pool tag: " + tag);
}
}
in.skipBytes(2); // access_flags
in.skipBytes(2); // this_class
int superClassIndex = in.readUnsignedShort();
Integer nameIndex = classInfo.get(superClassIndex);
if (nameIndex != null) {
return utf8Constants.get(nameIndex).replace("/", ".");
}
} catch (IOException e) {
return null;
}
return null;
}
public static Set<String> getInterfaceNames(byte[] classBytes) {
Set<String> interfaces = new HashSet<>();
try (DataInputStream in = new DataInputStream(new ByteArrayInputStream(classBytes))) {
in.skipBytes(8); // magic + minor + major
int constantPoolCount = in.readUnsignedShort();
Map<Integer, String> utf8Constants = new HashMap<>();
Map<Integer, Integer> classInfo = new HashMap<>();
for (int i = 1; i < constantPoolCount; i++) {
int tag = in.readUnsignedByte();
switch (tag) {
case 1 -> utf8Constants.put(i, in.readUTF()); // Utf8
case 3, 4 -> in.skipBytes(4); // int, float
case 5, 6 -> { in.skipBytes(8); i++; } // long, double
case 7 -> classInfo.put(i, in.readUnsignedShort()); // Class -> name_index
case 8 -> in.readUnsignedShort(); // String
case 9, 10, 11, 12, 18 -> in.skipBytes(4); // Field/Method/InterfaceMethod/NameAndType/InvokeDynamic
case 15 -> in.skipBytes(3); // MethodHandle
case 16 -> in.skipBytes(2); // MethodType
case 17 -> in.skipBytes(4); // Dynamic
default -> throw new IOException("Bad constant pool tag: " + tag);
}
}
in.skipBytes(2); // access flags
in.skipBytes(2); // this class
in.skipBytes(2); // super class
int interfacesCount = in.readUnsignedShort();
for (int i = 0; i < interfacesCount; i++) {
int index = in.readUnsignedShort();
Integer nameIndex = classInfo.get(index);
if (nameIndex != null) {
String iface = utf8Constants.get(nameIndex);
if (iface != null) {
interfaces.add(iface.replace("/", "."));
}
}
}
return interfaces;
} catch (IOException e) {
return interfaces;
}
}
public Set<Class<?>> getScannedClasses() {
return Collections.unmodifiableSet(scannedClasses);
}
public Map<String, Object> getScannedClassInstances() {
return Collections.unmodifiableMap(scannedClassInstances);
}
}

View File

@ -11,7 +11,6 @@ import com.io.yutian.elementoriginlib.logger.Logger;
import com.io.yutian.elementoriginlib.serialize.serializers.*; import com.io.yutian.elementoriginlib.serialize.serializers.*;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import java.util.Objects;
import java.util.UUID; import java.util.UUID;
public class SerializeHelper { public class SerializeHelper {
@ -26,11 +25,11 @@ public class SerializeHelper {
objectMapper = new ObjectMapper(); objectMapper = new ObjectMapper();
objectMapper.setVisibility( objectMapper.setVisibility(
VisibilityChecker.Std.defaultInstance() VisibilityChecker.Std.defaultInstance()
.withFieldVisibility(JsonAutoDetect.Visibility.ANY) .withFieldVisibility(JsonAutoDetect.Visibility.NONE)
.withGetterVisibility(JsonAutoDetect.Visibility.NONE) .withGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withSetterVisibility(JsonAutoDetect.Visibility.NONE) .withSetterVisibility(JsonAutoDetect.Visibility.NONE)
.withIsGetterVisibility(JsonAutoDetect.Visibility.NONE) .withIsGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withCreatorVisibility(JsonAutoDetect.Visibility.NONE) .withCreatorVisibility(JsonAutoDetect.Visibility.ANY)
); );
objectMapper.registerModule(new AfterburnerModule()); objectMapper.registerModule(new AfterburnerModule());

View File

@ -0,0 +1,16 @@
package com.io.yutian.elementoriginlib.shadowloader;
import javassist.ClassPool;
import javassist.CtClass;
public class BytecodeRewriter {
public static byte[] rewriteClass(byte[] originalBytes, String originalName, String newName) throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass ct = pool.makeClass(new java.io.ByteArrayInputStream(originalBytes));
ct.setName(newName);
byte[] result = ct.toBytecode();
ct.detach();
return result;
}
}

View File

@ -0,0 +1,12 @@
package com.io.yutian.elementoriginlib.shadowloader;
public class ShadowClassLoader extends ClassLoader {
public ShadowClassLoader(ClassLoader parent) {
super(parent);
}
public Class<?> define(String name, byte[] bytecode) {
return defineClass(name, bytecode, 0, bytecode.length);
}
}

View File

@ -33,6 +33,13 @@ public class ClassUtil {
return false; return false;
} }
public static Class<?> getWrapperType(Class<?> clazz) {
if (clazz == null) {
return null;
}
return PRIMITIVE_TO_WRAPPER.getOrDefault(clazz, clazz);
}
public static String getJar(Plugin plugin) { public static String getJar(Plugin plugin) {
String p = plugin.getClass().getProtectionDomain().getCodeSource().getLocation().getPath(); String p = plugin.getClass().getProtectionDomain().getCodeSource().getLocation().getPath();
return p.substring(1); return p.substring(1);

View File

@ -0,0 +1,314 @@
package com.io.yutian.elementoriginlib.util;
import com.google.common.collect.ImmutableMap;
import net.md_5.bungee.api.ChatColor;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.ThreadSafe;
import java.awt.*;
import java.util.*;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
public class ColorUtil {
public static final List<String> SPECIAL_COLORS = Arrays.asList("&l", "&n", "&o", "&k", "&m");
private static final Map<Color, ChatColor> COLORS = ImmutableMap.<Color, ChatColor>builder()
.put(new Color(0), ChatColor.getByChar('0'))
.put(new Color(170), ChatColor.getByChar('1'))
.put(new Color(43520), ChatColor.getByChar('2'))
.put(new Color(43690), ChatColor.getByChar('3'))
.put(new Color(11141120), ChatColor.getByChar('4'))
.put(new Color(11141290), ChatColor.getByChar('5'))
.put(new Color(16755200), ChatColor.getByChar('6'))
.put(new Color(11184810), ChatColor.getByChar('7'))
.put(new Color(5592405), ChatColor.getByChar('8'))
.put(new Color(5592575), ChatColor.getByChar('9'))
.put(new Color(5635925), ChatColor.getByChar('a'))
.put(new Color(5636095), ChatColor.getByChar('b'))
.put(new Color(16733525), ChatColor.getByChar('c'))
.put(new Color(16733695), ChatColor.getByChar('d'))
.put(new Color(16777045), ChatColor.getByChar('e'))
.put(new Color(16777215), ChatColor.getByChar('f'))
.build();
private static final List<Pattern> PATTERNS = Arrays.asList(new GradientPattern(), new SolidPattern(), new RainbowPattern());
private static final LruCache LRU_CACHE = new LruCache(512);
@Nonnull
public static String process(@Nonnull String string) {
String result = LRU_CACHE.getResult(string);
if (result != null) {
return result;
}
String input = string;
for (Pattern pattern : PATTERNS) {
string = pattern.process(string);
}
string = ChatColor.translateAlternateColorCodes('&', string);
LRU_CACHE.put(input, string);
return string;
}
@Nonnull
public static List<String> process(@Nonnull List<String> strings) {
strings.replaceAll(ColorUtil::process);
return strings;
}
@Nonnull
public static String color(@Nonnull String string, @Nonnull Color color) {
return ChatColor.of(color) + string;
}
@Nonnull
public static String color(@Nonnull String string, @Nonnull Color start, @Nonnull Color end) {
StringBuilder specialColors = new StringBuilder();
for (String color : SPECIAL_COLORS) {
if (string.contains(color)) {
specialColors.append(color);
string = string.replace(color, "");
}
}
StringBuilder stringBuilder = new StringBuilder();
ChatColor[] colors = createGradient(start, end, string.length());
String[] characters = string.split("");
for (int i = 0; i < string.length(); i++) {
stringBuilder.append(colors[i]).append(specialColors).append(characters[i]);
}
return stringBuilder.toString();
}
@Nonnull
public static String rainbow(@Nonnull String string, float saturation) {
StringBuilder specialColors = new StringBuilder();
for (String color : SPECIAL_COLORS) {
if (string.contains(color)) {
specialColors.append(color);
string = string.replace(color, "");
}
}
StringBuilder stringBuilder = new StringBuilder();
ChatColor[] colors = createRainbow(string.length(), saturation);
String[] characters = string.split("");
for (int i = 0; i < string.length(); i++) {
stringBuilder.append(colors[i]).append(specialColors).append(characters[i]);
}
return stringBuilder.toString();
}
@Nonnull
public static ChatColor getColor(@Nonnull String string) {
return ChatColor.of(new Color(Integer.parseInt(string, 16)));
}
@Nonnull
public static String stripColorFormatting(@Nonnull String string) {
return string.replaceAll("[&§][a-f0-9lnokm]|<[/]?\\w{5,8}(:[0-9A-F]{6})?>", "");
}
@Nonnull
private static ChatColor[] createRainbow(int step, float saturation) {
ChatColor[] colors = new ChatColor[step];
double colorStep = (1.00 / step);
for (int i = 0; i < step; i++) {
Color color = Color.getHSBColor((float) (colorStep * i), saturation, saturation);
colors[i] = ChatColor.of(color);
}
return colors;
}
@Nonnull
private static ChatColor[] createGradient(@Nonnull Color start, @Nonnull Color end, int step) {
if (step <= 1) {
return new ChatColor[]{ChatColor.WHITE, ChatColor.WHITE, ChatColor.WHITE};
}
ChatColor[] colors = new ChatColor[step];
int stepR = Math.abs(start.getRed() - end.getRed()) / (step - 1);
int stepG = Math.abs(start.getGreen() - end.getGreen()) / (step - 1);
int stepB = Math.abs(start.getBlue() - end.getBlue()) / (step - 1);
int[] direction = new int[]{
start.getRed() < end.getRed() ? +1 : -1,
start.getGreen() < end.getGreen() ? +1 : -1,
start.getBlue() < end.getBlue() ? +1 : -1
};
for (int i = 0; i < step; i++) {
Color color = new Color(start.getRed() + ((stepR * i) * direction[0]), start.getGreen() + ((stepG * i) * direction[1]), start.getBlue() + ((stepB * i) * direction[2]));
colors[i] = ChatColor.of(color);
}
return colors;
}
@Nonnull
private static ChatColor getClosestColor(Color color) {
Color nearestColor = null;
double nearestDistance = Integer.MAX_VALUE;
for (Color constantColor : COLORS.keySet()) {
double distance = Math.pow(color.getRed() - constantColor.getRed(), 2) + Math.pow(color.getGreen() - constantColor.getGreen(), 2) + Math.pow(color.getBlue() - constantColor.getBlue(), 2);
if (nearestDistance > distance) {
nearestColor = constantColor;
nearestDistance = distance;
}
}
return COLORS.get(nearestColor);
}
@ThreadSafe
private static class LruCache {
private final Deque<String> deque = new LinkedList<>();
private final Map<String, LruElement> map = new ConcurrentHashMap<>();
private final int maxSize;
public LruCache(int maxSize) {
this.maxSize = maxSize;
}
public String getResult(String input) {
if (input != null && map.containsKey(input)) {
LruElement curr = map.get(input);
synchronized (deque) {
deque.remove(input);
deque.addFirst(input);
}
return curr.getResult();
}
return null;
}
public void put(String input, String result) {
if (input == null || result == null) {
return;
}
synchronized (deque) {
if (map.containsKey(input)) {
deque.remove(input);
} else {
int size = deque.size();
if (size == maxSize && size > 0) {
String temp = deque.removeLast();
map.remove(temp);
}
}
LruElement newObj = new LruElement(input, result);
deque.addFirst(input);
map.put(input, newObj);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
LruCache lruCache = (LruCache) o;
return maxSize == lruCache.maxSize && deque.equals(lruCache.deque) && map.equals(lruCache.map);
}
@Override
public int hashCode() {
int result = deque.hashCode();
result = 31 * result + map.hashCode();
result = 31 * result + maxSize;
return result;
}
}
private static class LruElement {
private final String input;
private final String result;
public LruElement(String input, String result) {
this.input = input;
this.result = result;
}
public String getInput() {
return input;
}
public String getResult() {
return result;
}
}
private static interface Pattern {
String process(String string);
}
private static class GradientPattern implements Pattern {
private static final java.util.regex.Pattern PATTERN = java.util.regex.Pattern.compile(
"[<{]#([A-Fa-f0-9]{6})[}>](((?![<{]#[A-Fa-f0-9]{6}[}>]).)*)[<{]/#([A-Fa-f0-9]{6})[}>]"
);
public String process(String string) {
Matcher matcher = PATTERN.matcher(string);
while (matcher.find()) {
String start = matcher.group(1);
String content = matcher.group(2);
String end = matcher.group(4);
string = string.replace(
matcher.group(),
color(
content,
new Color(Integer.parseInt(start, 16)),
new Color(Integer.parseInt(end, 16))
)
);
}
return string;
}
}
private static class RainbowPattern implements Pattern {
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("<RAINBOW([0-9]{1,3})>(.*?)</RAINBOW>");
public String process(String string) {
Matcher matcher = pattern.matcher(string);
while (matcher.find()) {
String saturation = matcher.group(1);
String content = matcher.group(2);
string = string.replace(matcher.group(), rainbow(content, Float.parseFloat(saturation)));
}
return string;
}
}
private static class SolidPattern implements Pattern {
public static final java.util.regex.Pattern PATTERN = java.util.regex.Pattern.compile("[<{]#([A-Fa-f0-9]{6})[}>]|[&]?#([A-Fa-f0-9]{6})");
public String process(String string) {
Matcher matcher = PATTERN.matcher(string);
while (matcher.find()) {
String color = matcher.group(1);
if (color == null) {
color = matcher.group(2);
}
string = string.replace(matcher.group(), getColor(color) + "");
}
return string;
}
}
}

View File

@ -1,7 +1,10 @@
package com.io.yutian.elementoriginlib.util; package com.io.yutian.elementoriginlib.util;
import com.io.yutian.elementoriginlib.ElementOriginLib;
import com.io.yutian.elementoriginlib.logger.Logger;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.Property;
import net.kyori.adventure.text.Component;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.attribute.Attribute; import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeModifier; import org.bukkit.attribute.AttributeModifier;
@ -10,11 +13,10 @@ import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.EnchantmentStorageMeta; import org.bukkit.inventory.meta.*;
import org.bukkit.inventory.meta.FireworkMeta; import org.bukkit.inventory.meta.trim.ArmorTrim;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffect;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.*; import java.util.*;
@ -23,168 +25,40 @@ public class ItemStackBuilder {
private ItemStack itemStack; private ItemStack itemStack;
private Material type;
private int amount;
private short data;
private ItemMeta meta;
private String displayName;
private int customModelData;
private List<String> lore;
private Map<Enchantment, Integer> enchants;
private Set<ItemFlag> itemFlags;
private List<PotionEffect> potionEffects;
private List<Pattern> patterns;
private List<FireworkEffect> fireworkEffects;
private String skullTextures;
private UUID skullOwner;
public ItemStackBuilder(Material material) { public ItemStackBuilder(Material material) {
this.itemStack = new ItemStack(material); this.itemStack = new ItemStack(material);
this.type = material;
this.amount = 1;
this.data = 0;
this.meta = this.itemStack.getItemMeta();
this.displayName = this.meta.getDisplayName();
this.customModelData = this.meta.hasCustomModelData() ? this.meta.getCustomModelData() : -1;
this.lore = new ArrayList<>();
this.enchants = new HashMap<>();
this.itemFlags = new HashSet<>();
this.potionEffects = new ArrayList<>();
this.patterns = new ArrayList<>();
this.fireworkEffects = new ArrayList<>();
} }
public ItemStackBuilder(ItemStack item) { public ItemStackBuilder(ItemStack item) {
this.itemStack = item.clone(); this.itemStack = item.clone();
this.type = item.getType();
this.amount = item.getAmount();
this.data = item.getDurability();
this.meta = item.getItemMeta();
this.displayName = this.meta.getDisplayName();
this.customModelData = this.meta.hasCustomModelData() ? this.meta.getCustomModelData() : -1;
this.lore = this.meta.getLore() == null ? new ArrayList<>() : meta.getLore();
this.enchants = this.meta.getEnchants();
this.itemFlags = this.meta.getItemFlags();
this.potionEffects = new ArrayList<>();
this.patterns = new ArrayList<>();
this.fireworkEffects = new ArrayList<>();
} }
public ItemStack build() { public ItemStack build() {
ItemStack item = new ItemStack(type, amount); return itemStack;
item.setType(type);
item.setAmount(amount);
ItemMeta itemMeta = item.getItemMeta();
if (displayName != null) {
itemMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', displayName));
}
if (enchants != null) {
item.addUnsafeEnchantments(enchants);
}
if (lore != null) {
List<String> l = new ArrayList<>();
lore.forEach((s) -> {
l.add(ChatColor.translateAlternateColorCodes('&', s));
});
itemMeta.setLore(l);
}
if (this.customModelData != -1) {
itemMeta.setCustomModelData(customModelData);
}
if (itemFlags != null) {
for (ItemFlag flag : itemFlags) {
itemMeta.addItemFlags(flag);
}
}
if (fireworkEffects != null && fireworkEffects.size() > 0 && (type.equals(Material.FIREWORK_STAR) || type.equals(Material.FIREWORK_ROCKET))) {
FireworkMeta fireworkMeta = (FireworkMeta) itemMeta;
for (FireworkEffect effect : fireworkEffects) {
fireworkMeta.addEffect(effect);
}
}
if (skullTextures != null && type.equals(Material.PLAYER_HEAD)) {
SkullMeta skullMeta = (SkullMeta) itemMeta;
String uuid = UUID.randomUUID().toString();
GameProfile profile = new GameProfile(UUID.fromString(uuid), null);
profile.getProperties().put("textures", new Property("textures", skullTextures));
Field profileField;
try {
profileField = skullMeta.getClass().getDeclaredField("profile");
profileField.setAccessible(true);
profileField.set(skullMeta, profile);
} catch (NullPointerException | NoSuchFieldException | IllegalArgumentException | IllegalAccessException e1) {
}
} else if (skullOwner != null && type.equals(Material.PLAYER_HEAD)) {
SkullMeta skullMeta = (SkullMeta) itemMeta;
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(skullOwner);
if (offlinePlayer != null) {
skullMeta.setOwningPlayer(Bukkit.getOfflinePlayer(skullOwner));
}
}
item.setItemMeta(itemMeta);
return item;
} }
public int getAmount() { public int getAmount() {
return amount; return itemStack.getAmount();
} }
public Material getType() { public Material getType() {
return type; return itemStack.getType();
} }
public List<String> getLore() { public List<Component> getLore() {
return lore; return itemStack.getItemMeta().lore();
} }
public int getCustomModelData() { public int getCustomModelData() {
return customModelData; return itemStack.getItemMeta().getCustomModelData();
} }
public Map<Enchantment, Integer> getEnchants() { public Map<Enchantment, Integer> getEnchants() {
return enchants; return itemStack.getItemMeta().getEnchants();
} }
public Set<ItemFlag> getItemFlags() { public Set<ItemFlag> getItemFlags() {
return itemFlags; return itemStack.getItemMeta().getItemFlags();
}
public List<PotionEffect> getPotionEffects() {
return potionEffects;
}
public List<FireworkEffect> getFireworkEffects() {
return fireworkEffects;
}
public List<Pattern> getPatterns() {
return patterns;
}
public String getSkullTextures() {
return skullTextures;
}
public String getDisplayName() {
return displayName;
}
public short getData() {
return data;
}
public UUID getSkullOwner() {
return skullOwner;
} }
public ItemStackBuilder setItemStack(ItemStack item) { public ItemStackBuilder setItemStack(ItemStack item) {
@ -193,189 +67,285 @@ public class ItemStackBuilder {
} }
public ItemStackBuilder setType(Material type) { public ItemStackBuilder setType(Material type) {
this.type = type; this.itemStack.withType(type);
return this; return this;
} }
public ItemStackBuilder setCustomModelData(int customModelData) { public ItemStackBuilder setCustomModelData(int customModelData) {
this.customModelData = customModelData; this.itemStack.editMeta((meta)-> meta.setCustomModelData(customModelData));
return this; return this;
} }
public ItemStackBuilder setAmount(int amount) { public ItemStackBuilder setAmount(int amount) {
this.amount = amount; this.itemStack.setAmount(amount);
return this;
}
public ItemStackBuilder setData(int data) {
if (data > 255) {
data = 255;
}
this.data = (short) data;
return this;
}
public ItemStackBuilder setData(short data) {
this.data = data;
return this;
}
public ItemStackBuilder setItemMeta(ItemMeta meta) {
this.meta = meta;
return this; return this;
} }
public ItemStackBuilder setDisplayName(String name) { public ItemStackBuilder setDisplayName(String name) {
this.displayName = name; this.itemStack.editMeta((meta)-> meta.displayName(Component.text(name)));
return this;
}
public ItemStackBuilder setDisplayName(Component name) {
this.itemStack.editMeta((meta)-> meta.displayName(name));
return this; return this;
} }
public ItemStackBuilder setLore(List<String> loreList) { public ItemStackBuilder setLore(List<String> loreList) {
this.lore = loreList; List<Component> loreComponents = new ArrayList<>();
for (String lore : loreList) {
loreComponents.add(Component.text(lore));
}
this.itemStack.editMeta((meta)-> meta.lore(loreComponents));
return this; return this;
} }
public ItemStackBuilder setLore(String... lores) { public ItemStackBuilder setLore(String... lores) {
this.lore = new ArrayList<>(Arrays.asList(lores)); return setLore(List.of(lores));
return this;
} }
public ItemStackBuilder addLore(String lore) { public ItemStackBuilder addLore(String lore) {
this.lore.add(lore); List<Component> loreComponents = itemStack.getItemMeta().hasLore() ? itemStack.getItemMeta().lore() : new ArrayList<>();
loreComponents.add(Component.text(lore));
this.itemStack.editMeta((meta)-> meta.lore(loreComponents));
return this; return this;
} }
public ItemStackBuilder addLore(String... lores) { public ItemStackBuilder addLore(String... lores) {
this.lore.addAll(Arrays.asList(lores)); List<Component> loreComponents = itemStack.getItemMeta().hasLore() ? itemStack.getItemMeta().lore() : new ArrayList<>();
for (String lore : lores) {
loreComponents.add(Component.text(lore));
}
this.itemStack.editMeta((meta)-> meta.lore(loreComponents));
return this; return this;
} }
public ItemStackBuilder addLore(List<String> lores) { public ItemStackBuilder addLore(Component... lores) {
for (String lore : lores) { List<Component> loreComponents = itemStack.getItemMeta().hasLore() ? itemStack.getItemMeta().lore() : new ArrayList<>();
this.lore.add(lore); for (Component lore : lores) {
loreComponents.add(lore);
} }
this.itemStack.editMeta((meta)-> meta.lore(loreComponents));
return this;
}
public ItemStackBuilder addLore(List<Component> lores) {
List<Component> loreComponents = itemStack.getItemMeta().hasLore() ? itemStack.getItemMeta().lore() : new ArrayList<>();
loreComponents.addAll(lores);
this.itemStack.editMeta((meta)-> meta.lore(loreComponents));
return this; return this;
} }
public ItemStackBuilder addAttributeModifier(Attribute attribute, AttributeModifier attributeModifier) { public ItemStackBuilder addAttributeModifier(Attribute attribute, AttributeModifier attributeModifier) {
this.meta.addAttributeModifier(attribute, attributeModifier); this.itemStack.editMeta((meta)-> meta.addAttributeModifier(attribute, attributeModifier));
return this; return this;
} }
public ItemStackBuilder removeAttributeModifier(Attribute attribute) { public ItemStackBuilder removeAttributeModifier(Attribute attribute) {
this.meta.removeAttributeModifier(attribute); this.itemStack.editMeta((meta)-> meta.removeAttributeModifier(attribute));
return this; return this;
} }
public ItemStackBuilder removeAttributeModifier(EquipmentSlot equipmentSlot) { public ItemStackBuilder removeAttributeModifier(EquipmentSlot equipmentSlot) {
this.meta.removeAttributeModifier(equipmentSlot); this.itemStack.editMeta((meta)-> meta.removeAttributeModifier(equipmentSlot));
return this; return this;
} }
public ItemStackBuilder removeAttributeModifier(Attribute attribute, AttributeModifier attributeModifier) { public ItemStackBuilder removeAttributeModifier(Attribute attribute, AttributeModifier attributeModifier) {
this.meta.removeAttributeModifier(attribute, attributeModifier); this.itemStack.editMeta((meta)-> meta.removeAttributeModifier(attribute, attributeModifier));
return this; return this;
} }
public ItemStackBuilder addEnchant(Enchantment ench, int level) { public ItemStackBuilder addEnchant(Enchantment ench, int level) {
this.enchants.put(ench, level); this.itemStack.editMeta((meta)-> meta.addEnchant(ench, level, true));
return this; return this;
} }
public ItemStackBuilder removeEnchant(Enchantment ench) { public ItemStackBuilder removeEnchant(Enchantment ench) {
this.enchants.remove(ench); this.itemStack.editMeta((meta)-> meta.removeEnchant(ench));
return this; return this;
} }
public ItemStackBuilder setEnchants(Map<Enchantment, Integer> enchants) { public ItemStackBuilder setEnchants(Map<Enchantment, Integer> enchants) {
this.enchants = enchants; this.itemStack.editMeta((meta)->{
return this; meta.removeEnchantments();
for (Map.Entry<Enchantment, Integer> entry : enchants.entrySet()) {
meta.addEnchant(entry.getKey(), entry.getValue(), true);
} }
});
public ItemStackBuilder setEnchants(List<String> enchants) {
this.enchants = getEnchantsFromList(enchants);
return this; return this;
} }
public ItemStackBuilder setItemFlags(Set<ItemFlag> itemFlags) { public ItemStackBuilder setItemFlags(Set<ItemFlag> itemFlags) {
this.itemFlags = itemFlags; this.itemStack.editMeta((meta)-> {
meta.removeItemFlags(ItemFlag.values());
for (ItemFlag itemFlag : itemFlags) {
meta.addItemFlags(itemFlag);
}
});
return this; return this;
} }
public ItemStackBuilder addItemFlags(ItemFlag[] itemFlags) { public ItemStackBuilder addItemFlags(ItemFlag[] itemFlags) {
this.itemFlags.addAll(Arrays.asList(itemFlags)); this.itemStack.editMeta((meta)-> {
meta.removeItemFlags(ItemFlag.values());
for (ItemFlag itemFlag : itemFlags) {
meta.addItemFlags(itemFlag);
}
});
return this; return this;
} }
public ItemStackBuilder addItemFlags(ItemFlag itemFlag) { public ItemStackBuilder addItemFlags(ItemFlag itemFlag) {
this.itemFlags.add(itemFlag); this.itemStack.editMeta((meta)-> meta.addItemFlags(itemFlag));
return this;
}
public ItemStackBuilder setUnbreakable(boolean unbreakable) {
this.itemStack.editMeta((meta)-> meta.setUnbreakable(unbreakable));
return this;
}
public ItemStackBuilder setHideTooltip(boolean hideTooltip) {
this.itemStack.editMeta((meta)-> meta.setHideTooltip(hideTooltip));
return this;
}
public ItemStackBuilder setFireResistant(boolean fireResistant) {
this.itemStack.editMeta((meta)-> meta.setFireResistant(fireResistant));
return this;
}
public ItemStackBuilder setMaxStackSize(int maxStackSize) {
this.itemStack.editMeta((meta)-> meta.setCustomModelData(maxStackSize));
return this;
}
public ItemStackBuilder setEnchantmentGlint(boolean enchantmentGlint) {
this.itemStack.editMeta((meta)-> meta.setEnchantmentGlintOverride(enchantmentGlint));
return this; return this;
} }
public ItemStackBuilder addPotionEffect(PotionEffect potionEffect) { public ItemStackBuilder addPotionEffect(PotionEffect potionEffect) {
this.potionEffects.add(potionEffect); if (!(itemStack.getItemMeta() instanceof PotionMeta)) {
ElementOriginLib.LOGGER.warn("ItemMeta is not " + PotionMeta.class.getName());
return this;
}
this.itemStack.editMeta(PotionMeta.class, (meta)-> meta.addCustomEffect(potionEffect, true));
return this;
}
public ItemStackBuilder removePotionEffect(PotionEffect potionEffect) {
if (!(itemStack.getItemMeta() instanceof PotionMeta)) {
ElementOriginLib.LOGGER.warn("ItemMeta is not " + PotionMeta.class.getName());
return this;
}
this.itemStack.editMeta(PotionMeta.class, (meta)-> meta.removeCustomEffect(potionEffect.getType()));
return this;
}
public ItemStackBuilder clearPotionEffects() {
if (!(itemStack.getItemMeta() instanceof PotionMeta)) {
ElementOriginLib.LOGGER.warn("ItemMeta is not " + PotionMeta.class.getName());
return this;
}
this.itemStack.editMeta(PotionMeta.class, (meta)-> {
meta.clearCustomEffects();
});
return this; return this;
} }
public ItemStackBuilder addPattern(Pattern pattern) { public ItemStackBuilder addPattern(Pattern pattern) {
this.patterns.add(pattern); if (!(itemStack.getItemMeta() instanceof BannerMeta)) {
ElementOriginLib.LOGGER.warn("ItemMeta is not " + BannerMeta.class.getName());
return this;
}
this.itemStack.editMeta(BannerMeta.class, (meta)-> meta.addPattern(pattern));
return this; return this;
} }
public ItemStackBuilder addFireworkEffect(FireworkEffect fireworkEffect) { public ItemStackBuilder removePattern(int index) {
this.fireworkEffects.add(fireworkEffect); if (!(itemStack.getItemMeta() instanceof BannerMeta)) {
ElementOriginLib.LOGGER.warn("ItemMeta is not " + BannerMeta.class.getName());
return this;
}
this.itemStack.editMeta(BannerMeta.class, (meta)-> meta.removePattern(index));
return this;
}
public ItemStackBuilder setPatterns(List<Pattern> patterns) {
if (!(itemStack.getItemMeta() instanceof BannerMeta)) {
ElementOriginLib.LOGGER.warn("ItemMeta is not " + BannerMeta.class.getName());
return this;
}
this.itemStack.editMeta(BannerMeta.class, (meta)-> meta.setPatterns(patterns));
return this;
}
public ItemStackBuilder setFireworkEffect(FireworkEffect fireworkEffect) {
if (!(itemStack.getItemMeta() instanceof FireworkMeta)) {
ElementOriginLib.LOGGER.warn("ItemMeta is not " + FireworkMeta.class.getName());
return this;
}
this.itemStack.editMeta(FireworkMeta.class, (meta)-> meta.addEffect(fireworkEffect));
return this;
}
public ItemStackBuilder clearFireworkEffects() {
if (!(itemStack.getItemMeta() instanceof FireworkMeta)) {
ElementOriginLib.LOGGER.warn("ItemMeta is not " + FireworkMeta.class.getName());
return this;
}
this.itemStack.editMeta(FireworkMeta.class, (meta)-> meta.clearEffects());
return this; return this;
} }
public ItemStackBuilder setSkullTextures(String skullTextures) { public ItemStackBuilder setSkullTextures(String skullTextures) {
this.skullTextures = skullTextures; if (!(itemStack.getItemMeta() instanceof SkullMeta)) {
ElementOriginLib.LOGGER.warn("ItemMeta is not " + SkullMeta.class.getName());
return this;
}
this.itemStack.editMeta(SkullMeta.class, (meta)-> {
String uuid = UUID.randomUUID().toString();
GameProfile profile = new GameProfile(UUID.fromString(uuid), "Skull");
profile.getProperties().put("textures", new Property("textures", skullTextures));
Field profileField;
try {
profileField = meta.getClass().getDeclaredField("profile");
profileField.setAccessible(true);
profileField.set(meta, profile);
} catch (NullPointerException | NoSuchFieldException | IllegalArgumentException | IllegalAccessException e1) {
}
});
return this; return this;
} }
public ItemStackBuilder setSkullOwner(UUID skullOwner) { public ItemStackBuilder setSkullOwner(String skullOwner) {
this.skullOwner = skullOwner; if (!(itemStack.getItemMeta() instanceof SkullMeta)) {
ElementOriginLib.LOGGER.warn("ItemMeta is not " + SkullMeta.class.getName());
return this;
}
this.itemStack.editMeta(SkullMeta.class, (meta)-> meta.setOwningPlayer(Bukkit.getOfflinePlayer(skullOwner)));
return this; return this;
} }
protected Map<Enchantment, Integer> getEnchantsFromList(List<String> enchants) { public ItemStackBuilder setColor(Color color) {
Map<Enchantment, Integer> map = new HashMap<>(); if (!(itemStack.getItemMeta() instanceof LeatherArmorMeta)) {
if (enchants == null) { ElementOriginLib.LOGGER.warn("ItemMeta is not " + LeatherArmorMeta.class.getName());
return map; return this;
} }
for (String s : enchants) { this.itemStack.editMeta(LeatherArmorMeta.class, (meta)-> meta.setColor(color));
if (s.contains(":")) { return this;
String[] part = s.split(":");
Enchantment en = Enchantment.getByName(part[0]);
if (en == null) {
continue;
}
map.put(en, Integer.parseInt(part[1]));
}
}
return map;
} }
protected static ItemStack setEnchants(ItemStack stack, List<String> enchants) { public ItemStackBuilder setTrim(ArmorTrim trim) {
if (enchants == null) { if (!(itemStack.getItemMeta() instanceof ArmorMeta)) {
return stack; ElementOriginLib.LOGGER.warn("ItemMeta is not " + ArmorMeta.class.getName());
return this;
} }
for (String s : enchants) { this.itemStack.editMeta(ArmorMeta.class, (meta)-> meta.setTrim(trim));
if (s.contains(":")) { return this;
String[] part = s.split(":");
Enchantment en = Enchantment.getByName(part[0]);
if (en == null) {
continue;
}
if (stack.getType() != Material.ENCHANTED_BOOK) {
stack.addUnsafeEnchantment(en, Integer.parseInt(part[1]));
} else {
EnchantmentStorageMeta esm = (EnchantmentStorageMeta) stack.getItemMeta();
esm.addStoredEnchant(en, Integer.parseInt(part[1]), true);
stack.setItemMeta((ItemMeta) esm);
}
}
}
return stack;
} }
private void setField(Object instance, String name, Object value) throws ReflectiveOperationException { private void setField(Object instance, String name, Object value) throws ReflectiveOperationException {

View File

@ -1,19 +1,19 @@
package com.io.yutian.elementoriginlib.util; package com.io.yutian.elementoriginlib.util;
import com.io.yutian.elementoriginlib.ElementOriginLib; import com.io.yutian.elementoriginlib.ElementOriginLib;
import com.io.yutian.elementoriginlib.expiringmap.ExpirationPolicy;
import com.io.yutian.elementoriginlib.expiringmap.ExpiringMap;
import org.json.JSONObject; import org.json.JSONObject;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class LangUtil { public class LangUtil {
private static ExpiringMap<String, String> expiringMap = ExpiringMap.builder().expiration(3, TimeUnit.MINUTES).expirationPolicy(ExpirationPolicy.CREATED).build(); private static Map<String, String> expiringMap = new HashMap<>();
private static JSONObject jsonObject = new JSONObject(); private static JSONObject jsonObject = new JSONObject();
public static String getLang(String key) { public static String getLang(String key) {

View File

@ -1,23 +0,0 @@
package com.io.yutian.elementoriginlib.util;
import org.bukkit.Material;
import java.util.UUID;
public class SkullBuilder extends ItemStackBuilder {
public SkullBuilder() {
super(Material.PLAYER_HEAD);
}
public SkullBuilder(String textures) {
super(Material.PLAYER_HEAD);
setSkullTextures(textures);
}
public SkullBuilder(UUID uuid) {
super(Material.PLAYER_HEAD);
setSkullOwner(uuid);
}
}

View File

@ -0,0 +1,347 @@
package com.io.yutian.elementoriginlib.util;
import com.io.yutian.elementoriginlib.exception.ItemStatDataLoadException;
import com.io.yutian.elementoriginlib.item.stat.data.*;
import org.jetbrains.annotations.NotNull;
import java.util.*;
public class StatDataUtil {
public static BooleanData loadBooleanDataAsObject(@NotNull Object value) throws ItemStatDataLoadException {
if (Objects.isNull(value)) {
throw new ItemStatDataLoadException("Invalid value: null");
}
try {
if (value instanceof Boolean bool) {
return new BooleanData(bool);
} else if (value instanceof String arg) {
boolean parsed = Boolean.parseBoolean(arg);
if (!arg.equalsIgnoreCase("true") && !arg.equalsIgnoreCase("false")) {
throw new ItemStatDataLoadException("Invalid boolean string: " + arg);
}
return new BooleanData(parsed);
} else if (value instanceof Byte b) {
return new BooleanData(b == 1);
} else if (value instanceof Integer i) {
return new BooleanData(i == 1);
} else {
throw new ItemStatDataLoadException("Invalid boolean value: " + value);
}
} catch (ClassCastException e) {
throw new ItemStatDataLoadException("Invalid type: " + value.getClass(), e);
}
}
public static DoubleListData loadDoubleListDataAsObject(@NotNull Object value) throws ItemStatDataLoadException {
if (Objects.isNull(value)) {
throw new ItemStatDataLoadException("Invalid value: null");
}
try {
if (value instanceof List<?> list) {
List<Double> doubleList = new ArrayList<>();
for (Object item : list) {
if (item instanceof Double d) {
doubleList.add(d);
} else if (item instanceof String str) {
try {
doubleList.add(Double.parseDouble(str));
} catch (NumberFormatException e) {
throw new ItemStatDataLoadException("Invalid string value for Double: " + str, e);
}
} else {
throw new ItemStatDataLoadException("List contains non-double element: " + item);
}
}
return new DoubleListData(doubleList);
} else if (value instanceof double[] array) {
List<Double> doubleList = new ArrayList<>();
for (double d : array) {
doubleList.add(d);
}
return new DoubleListData(doubleList);
} else if (value instanceof Double[] array) {
List<Double> doubleList = new ArrayList<>(Arrays.asList(array));
return new DoubleListData(doubleList);
} else if (value instanceof String str) {
List<Double> doubleList = new ArrayList<>();
String[] items = str.split(",");
for (String item : items) {
try {
doubleList.add(Double.parseDouble(item.trim()));
} catch (NumberFormatException e) {
throw new ItemStatDataLoadException("Invalid number format in string: " + item, e);
}
}
return new DoubleListData(doubleList);
} else {
throw new ItemStatDataLoadException("Invalid value type for DoubleListData: " + value);
}
} catch (Exception e) {
throw new ItemStatDataLoadException(e);
}
}
public static DoubleData loadDoubleDataAsObject(@NotNull Object value) throws ItemStatDataLoadException {
if (Objects.isNull(value)) {
throw new ItemStatDataLoadException("Invalid value: null");
}
try {
if (value instanceof Double d) {
return new DoubleData(d);
} else if (value instanceof String arg) {
try {
return new DoubleData(Double.parseDouble(arg));
} catch (NumberFormatException e) {
throw new ItemStatDataLoadException("Invalid double string: " + arg, e);
}
} else if (value instanceof Byte b) {
return new DoubleData((double) b);
} else if (value instanceof Integer i) {
return new DoubleData((double) i);
} else if (value instanceof Long l) {
return new DoubleData((double) l);
} else {
throw new ItemStatDataLoadException("Invalid double value: " + value);
}
} catch (Exception e) {
throw new ItemStatDataLoadException(e);
}
}
public static <E extends Enum> EnumListData<E> loadEnumListDataAsObject(Class<E> clazz, @NotNull Object value) throws ItemStatDataLoadException {
if (Objects.isNull(value)) {
throw new ItemStatDataLoadException("Invalid value: null");
}
try {
if (value instanceof List<?> list) {
List<E> enumList = new ArrayList<>();
for (Object item : list) {
if (item instanceof String str) {
try {
E enumConstant = (E) Enum.valueOf(clazz, str);
enumList.add(enumConstant);
} catch (IllegalArgumentException e) {
throw new ItemStatDataLoadException("Invalid enum string: " + str, e);
}
} else if (item instanceof Integer i) {
E[] enumConstants = clazz.getEnumConstants();
if (i < 0 || i >= enumConstants.length) {
throw new ItemStatDataLoadException("Invalid enum ordinal: " + i);
}
enumList.add(enumConstants[i]);
} else if (item instanceof Enum<?> enumItem) {
enumList.add((E) enumItem);
} else {
throw new ItemStatDataLoadException("Invalid list element type: " + item);
}
}
return new EnumListData<>(enumList);
} else if (value instanceof String str) {
List<E> enumList = new ArrayList<>();
String[] enumNames = str.split(",");
for (String enumName : enumNames) {
try {
E enumConstant = (E) Enum.valueOf(clazz, enumName.trim());
enumList.add(enumConstant);
} catch (IllegalArgumentException e) {
throw new ItemStatDataLoadException("Invalid enum string: " + enumName, e);
}
}
return new EnumListData<>(enumList);
} else {
throw new ItemStatDataLoadException("Invalid value type for EnumListData: " + value);
}
} catch (Exception e) {
throw new ItemStatDataLoadException(e);
}
}
public static <E extends Enum> EnumData<E> loadEnumDataAsObject(Class<E> clazz, @NotNull Object value) throws ItemStatDataLoadException {
if (Objects.isNull(value)) {
throw new ItemStatDataLoadException("Invalid value: null");
}
try {
if (value instanceof Enum<?> enumValue) {
return new EnumData<>((E) enumValue);
} else if (value instanceof String str) {
try {
E enumConstant = (E) Enum.valueOf(clazz, str);
return new EnumData<>(enumConstant);
} catch (IllegalArgumentException e) {
throw new ItemStatDataLoadException("Invalid enum string: " + str, e);
}
} else if (value instanceof Integer i) {
E[] enumConstants = clazz.getEnumConstants();
if (i < 0 || i >= enumConstants.length) {
throw new ItemStatDataLoadException("Invalid enum ordinal: " + i);
}
return new EnumData<>(enumConstants[i]);
} else {
throw new ItemStatDataLoadException("Invalid value type for EnumData: " + value);
}
} catch (Exception e) {
throw new ItemStatDataLoadException(e);
}
}
public static IntListData loadIntListDataAsObject(@NotNull Object value) throws ItemStatDataLoadException {
if (Objects.isNull(value)) {
throw new ItemStatDataLoadException("Invalid value: null");
}
try {
if (value instanceof List<?> list) {
List<Integer> intList = new ArrayList<>();
for (Object item : list) {
if (item instanceof Integer i) {
intList.add(i);
} else {
throw new ItemStatDataLoadException("List contains non-integer element: " + item);
}
}
return new IntListData(intList);
} else if (value instanceof int[] array) {
List<Integer> intList = new ArrayList<>();
for (int i : array) {
intList.add(i);
}
return new IntListData(intList);
} else if (value instanceof String str) {
try {
List<Integer> intList = new ArrayList<>();
String[] items = str.split(",");
for (String item : items) {
intList.add(Integer.parseInt(item.trim()));
}
return new IntListData(intList);
} catch (NumberFormatException e) {
throw new ItemStatDataLoadException("Invalid integer string: " + str, e);
}
} else {
throw new ItemStatDataLoadException("Invalid value type for IntListData: " + value);
}
} catch (Exception e) {
throw new ItemStatDataLoadException(e);
}
}
public static IntData loadIntDataAsObject(@NotNull Object value) throws ItemStatDataLoadException {
if (Objects.isNull(value)) {
throw new ItemStatDataLoadException("Invalid value: null");
}
try {
if (value instanceof Integer i) {
return new IntData(i);
} else if (value instanceof String arg) {
try {
return new IntData(Integer.parseInt(arg));
} catch (NumberFormatException e) {
throw new ItemStatDataLoadException("Invalid integer string: " + arg, e);
}
} else if (value instanceof Byte b) {
return new IntData((int) b);
} else if (value instanceof Long l) {
if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) {
throw new ItemStatDataLoadException("Long value out of range for integer: " + l);
}
return new IntData(l.intValue());
} else if (value instanceof Double d) {
if (d < Integer.MIN_VALUE || d > Integer.MAX_VALUE) {
throw new ItemStatDataLoadException("Double value out of range for integer: " + d);
}
return new IntData((int) d.doubleValue());
} else if (value instanceof Float f) {
if (f < Integer.MIN_VALUE || f > Integer.MAX_VALUE) {
throw new ItemStatDataLoadException("Float value out of range for integer: " + f);
}
return new IntData((int) f.floatValue());
} else {
throw new ItemStatDataLoadException("Invalid integer value: " + value);
}
} catch (Exception e) {
throw new ItemStatDataLoadException(e);
}
}
public static MapData loadMapDataAsObject(@NotNull Object value) throws ItemStatDataLoadException {
if (Objects.isNull(value)) {
throw new ItemStatDataLoadException("Invalid value: null");
}
try {
if (value instanceof Map<?, ?> map) {
Map<String, Object> resultMap = new HashMap<>();
for (Map.Entry<?, ?> entry : map.entrySet()) {
if (entry.getKey() instanceof String key) {
resultMap.put(key, entry.getValue());
} else {
throw new ItemStatDataLoadException("Map key is not a String: " + entry.getKey());
}
}
return new MapData(resultMap);
} else {
throw new ItemStatDataLoadException("Invalid value type for MapData: " + value);
}
} catch (Exception e) {
throw new ItemStatDataLoadException(e);
}
}
public static StringListData loadStringListDataAsObject(@NotNull Object value) throws ItemStatDataLoadException {
if (Objects.isNull(value)) {
throw new ItemStatDataLoadException("Invalid value: null");
}
try {
if (value instanceof List<?> list) {
List<String> stringList = new ArrayList<>();
for (Object item : list) {
if (item instanceof String str) {
stringList.add(str);
} else {
throw new ItemStatDataLoadException("List contains non-string element: " + item);
}
}
return new StringListData(stringList);
} else if (value instanceof String[] array) {
// 处理 String[] 类型
return new StringListData(Arrays.asList(array));
} else if (value instanceof String str) {
List<String> stringList = new ArrayList<>();
stringList.add(str);
return new StringListData(stringList);
} else {
throw new ItemStatDataLoadException("Invalid value type for StringListData: " + value);
}
} catch (Exception e) {
throw new ItemStatDataLoadException(e);
}
}
public static StringData loadStringDataAsObject(@NotNull Object value) {
if (Objects.isNull(value)) {
throw new ItemStatDataLoadException("Invalid value: null");
}
return new StringData(value.toString());
}
public static UUIDData loadUUIDDataAsObject(@NotNull Object value) throws ItemStatDataLoadException {
if (Objects.isNull(value)) {
throw new ItemStatDataLoadException("Invalid value: null");
}
try {
if (value instanceof UUID uuid) {
return new UUIDData(uuid);
} else if (value instanceof String str) {
try {
return new UUIDData(UUID.fromString(str));
} catch (IllegalArgumentException e) {
throw new ItemStatDataLoadException("Invalid UUID string: " + str, e);
}
} else {
throw new ItemStatDataLoadException("Invalid UUID value: " + value);
}
} catch (Exception e) {
throw new ItemStatDataLoadException(e);
}
}
}

View File

@ -0,0 +1,26 @@
package com.io.yutian.elementoriginlib.util;
import java.util.List;
import java.util.function.Predicate;
public class Util {
public static <T> Predicate<T> allOf(List<? extends Predicate<T>> predicates) {
List<Predicate<T>> list = List.copyOf(predicates);
return switch (list.size()) {
case 0 -> object -> true;
case 1 -> list.get(0);
case 2 -> list.get(0).and(list.get(1));
default -> object -> {
for (Predicate<T> predicate : list) {
if (!predicate.test(object)) {
return false;
}
}
return true;
};
};
}
}

View File

View File

@ -5,4 +5,4 @@ api-version: '1.20'
authors: [ SuperYuTian ] authors: [ SuperYuTian ]
commands: commands:
elementoriginlib: elementoriginlib:
aliases: [ eol ] aliases: [ eolib ]