# Conflicts: # src/de/steamwar/sql/Event.java # src/de/steamwar/sql/EventFight.java # src/de/steamwar/sql/Mod.java # src/de/steamwar/sql/SteamwarUser.java # src/de/steamwar/sql/Team.java
Dieser Commit ist enthalten in:
Commit
6c60cc3ce6
@ -20,22 +20,28 @@
|
|||||||
package de.steamwar.command;
|
package de.steamwar.command;
|
||||||
|
|
||||||
import java.lang.annotation.*;
|
import java.lang.annotation.*;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Parameter;
|
import java.lang.reflect.Parameter;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.IntPredicate;
|
import java.util.function.BiPredicate;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public abstract class AbstractSWCommand<T> {
|
public abstract class AbstractSWCommand<T> {
|
||||||
|
|
||||||
|
private static final Map<Class<AbstractSWCommand<?>>, List<AbstractSWCommand<?>>> dependencyMap = new HashMap<>();
|
||||||
|
|
||||||
private Class<?> clazz; // This is used in createMappings()
|
private Class<?> clazz; // This is used in createMappings()
|
||||||
|
|
||||||
private boolean initialized = false;
|
private boolean initialized = false;
|
||||||
protected final List<SubCommand<T>> commandList = new ArrayList<>();
|
protected final List<SubCommand<T>> commandList = new ArrayList<>();
|
||||||
protected final List<SubCommand<T>> commandHelpList = new ArrayList<>();
|
protected final List<SubCommand<T>> helpCommandList = new ArrayList<>();
|
||||||
|
|
||||||
private final Map<String, AbstractTypeMapper<T, ?>> localTypeMapper = new HashMap<>();
|
private final Map<String, AbstractTypeMapper<T, ?>> localTypeMapper = new HashMap<>();
|
||||||
private final Map<String, AbstractValidator<T, ?>> localValidators = new HashMap<>();
|
private final Map<String, AbstractValidator<T, ?>> localValidators = new HashMap<>();
|
||||||
@ -46,6 +52,13 @@ public abstract class AbstractSWCommand<T> {
|
|||||||
|
|
||||||
protected AbstractSWCommand(Class<T> clazz, String command, String... aliases) {
|
protected AbstractSWCommand(Class<T> clazz, String command, String... aliases) {
|
||||||
this.clazz = clazz;
|
this.clazz = clazz;
|
||||||
|
|
||||||
|
PartOf partOf = this.getClass().getAnnotation(PartOf.class);
|
||||||
|
if (partOf != null) {
|
||||||
|
dependencyMap.computeIfAbsent((Class<AbstractSWCommand<?>>) partOf.value(), k -> new ArrayList<>()).add(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
createAndSafeCommand(command, aliases);
|
createAndSafeCommand(command, aliases);
|
||||||
unregister();
|
unregister();
|
||||||
register();
|
register();
|
||||||
@ -65,59 +78,22 @@ public abstract class AbstractSWCommand<T> {
|
|||||||
System.out.println(message.get());
|
System.out.println(message.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void sendMessage(T sender, String message, Object[] args) {}
|
protected void sendMessage(T sender, String message, Object[] args) {
|
||||||
|
}
|
||||||
|
|
||||||
private String[] quote(String[] args) {
|
protected void initialisePartOf(AbstractSWCommand parent) {
|
||||||
List<String> list = new ArrayList<>();
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
boolean quote = false;
|
|
||||||
for (String arg : args) {
|
|
||||||
if (arg.startsWith("\"") && arg.endsWith("\"")) {
|
|
||||||
list.add(arg);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (arg.startsWith("\"")) {
|
|
||||||
quote = true;
|
|
||||||
builder.append(arg);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (arg.endsWith("\"")) {
|
|
||||||
quote = false;
|
|
||||||
builder.append(" ").append(arg);
|
|
||||||
list.add(builder.toString());
|
|
||||||
builder = new StringBuilder();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (quote) {
|
|
||||||
builder.append(" ").append(arg);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
list.add(arg);
|
|
||||||
}
|
|
||||||
if (quote) {
|
|
||||||
commandSystemWarning(() -> "Missing closing quote in command");
|
|
||||||
}
|
|
||||||
if (builder.length() > 0) {
|
|
||||||
list.add(builder.toString());
|
|
||||||
}
|
|
||||||
return list.toArray(new String[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final void execute(T sender, String alias, String[] args) {
|
protected final void execute(T sender, String alias, String[] args) {
|
||||||
initialize();
|
initialize();
|
||||||
String[] finalArgs = quote(args);
|
|
||||||
List<Runnable> errors = new ArrayList<>();
|
List<Runnable> errors = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
if (!commandList.stream().anyMatch(s -> s.invoke(errors::add, sender, alias, finalArgs))) {
|
if (commandList.stream().noneMatch(s -> s.invoke(errors::add, sender, alias, args))) {
|
||||||
if (!errors.isEmpty()) {
|
errors.forEach(Runnable::run);
|
||||||
errors.forEach(Runnable::run);
|
} else return;
|
||||||
return;
|
if (errors.isEmpty() && helpCommandList.stream().noneMatch(s -> s.invoke(errors::add, sender, alias, args))) {
|
||||||
}
|
errors.forEach(Runnable::run);
|
||||||
commandHelpList.stream().anyMatch(s -> s.invoke((ignore) -> {
|
|
||||||
}, sender, alias, finalArgs));
|
|
||||||
}
|
}
|
||||||
} catch (CommandNoHelpException e) {
|
|
||||||
// Ignored
|
|
||||||
} catch (CommandFrameworkException e) {
|
} catch (CommandFrameworkException e) {
|
||||||
commandSystemError(sender, e);
|
commandSystemError(sender, e);
|
||||||
throw e;
|
throw e;
|
||||||
@ -126,87 +102,46 @@ public abstract class AbstractSWCommand<T> {
|
|||||||
|
|
||||||
protected final List<String> tabComplete(T sender, String alias, String[] args) throws IllegalArgumentException {
|
protected final List<String> tabComplete(T sender, String alias, String[] args) throws IllegalArgumentException {
|
||||||
initialize();
|
initialize();
|
||||||
String[] finalArgs = quote(args);
|
|
||||||
String string = args[args.length - 1].toLowerCase();
|
String string = args[args.length - 1].toLowerCase();
|
||||||
return commandList.stream()
|
return Stream.concat(commandList.stream(), helpCommandList.stream())
|
||||||
.filter(s -> !s.noTabComplete)
|
.filter(s -> !s.noTabComplete)
|
||||||
.map(s -> s.tabComplete(sender, finalArgs))
|
.map(s -> s.tabComplete(sender, args))
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.flatMap(Collection::stream)
|
.flatMap(Collection::stream)
|
||||||
.filter(s -> !s.isEmpty())
|
.filter(s -> !s.isEmpty())
|
||||||
.filter(s -> s.toLowerCase().startsWith(string))
|
.filter(s -> s.toLowerCase().startsWith(string) || string.startsWith(s.toLowerCase()))
|
||||||
.distinct()
|
.distinct()
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initialize() {
|
private synchronized void initialize() {
|
||||||
if (initialized) return;
|
if (initialized) return;
|
||||||
createMapping();
|
List<Method> methods = methods().stream()
|
||||||
}
|
.filter(this::validateMethod)
|
||||||
|
.collect(Collectors.toList());
|
||||||
private synchronized void createMapping() {
|
|
||||||
List<Method> methods = methods();
|
|
||||||
for (Method method : methods) {
|
for (Method method : methods) {
|
||||||
Cached cached = method.getAnnotation(Cached.class);
|
Cached cached = method.getAnnotation(Cached.class);
|
||||||
addMapper(Mapper.class, method, i -> i == 0, false, AbstractTypeMapper.class, (anno, typeMapper) -> {
|
this.<Mapper, AbstractTypeMapper<?, ?>>add(Mapper.class, method, (anno, typeMapper) -> {
|
||||||
TabCompletionCache.add(typeMapper, cached);
|
TabCompletionCache.add(typeMapper, cached);
|
||||||
if (anno.local()) {
|
(anno.local() ? ((Map) localTypeMapper) : SWCommandUtils.getMAPPER_FUNCTIONS()).put(anno.value(), typeMapper);
|
||||||
localTypeMapper.putIfAbsent(anno.value(), (AbstractTypeMapper<T, ?>) typeMapper);
|
|
||||||
} else {
|
|
||||||
SWCommandUtils.getMAPPER_FUNCTIONS().putIfAbsent(anno.value(), typeMapper);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
addMapper(ClassMapper.class, method, i -> i == 0, false, AbstractTypeMapper.class, (anno, typeMapper) -> {
|
this.<ClassMapper, AbstractTypeMapper<?, ?>>add(ClassMapper.class, method, (anno, typeMapper) -> {
|
||||||
TabCompletionCache.add(typeMapper, cached);
|
TabCompletionCache.add(typeMapper, cached);
|
||||||
if (anno.local()) {
|
(anno.local() ? ((Map) localTypeMapper) : SWCommandUtils.getMAPPER_FUNCTIONS()).put(anno.value().getName(), typeMapper);
|
||||||
localTypeMapper.putIfAbsent(anno.value().getTypeName(), (AbstractTypeMapper<T, ?>) typeMapper);
|
|
||||||
} else {
|
|
||||||
SWCommandUtils.getMAPPER_FUNCTIONS().putIfAbsent(anno.value().getTypeName(), typeMapper);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
addValidator(Validator.class, method, i -> i == 0, false, AbstractValidator.class, (anno, validator) -> {
|
this.<Validator, AbstractValidator<?, ?>>add(Validator.class, method, (anno, validator) -> {
|
||||||
if (anno.local()) {
|
(anno.local() ? ((Map) localValidators) : SWCommandUtils.getVALIDATOR_FUNCTIONS()).put(anno.value(), validator);
|
||||||
localValidators.putIfAbsent(anno.value(), (AbstractValidator<T, ?>) validator);
|
|
||||||
} else {
|
|
||||||
SWCommandUtils.getVALIDATOR_FUNCTIONS().putIfAbsent(anno.value(), validator);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
addValidator(ClassValidator.class, method, i -> i == 0, false, AbstractValidator.class, (anno, validator) -> {
|
this.<ClassValidator, AbstractValidator<?, ?>>add(ClassValidator.class, method, (anno, validator) -> {
|
||||||
if (anno.local()) {
|
(anno.local() ? ((Map) localValidators) : SWCommandUtils.getVALIDATOR_FUNCTIONS()).put(anno.value().getName(), validator);
|
||||||
localValidators.putIfAbsent(anno.value().getTypeName(), (AbstractValidator<T, ?>) validator);
|
|
||||||
} else {
|
|
||||||
SWCommandUtils.getVALIDATOR_FUNCTIONS().putIfAbsent(anno.value().getTypeName(), validator);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
for (Method method : methods) {
|
for (Method method : methods) {
|
||||||
add(Register.class, method, i -> i > 0, true, null, (anno, parameters) -> {
|
add(Register.class, method, true, (anno, parameters) -> {
|
||||||
if (!anno.help()) return;
|
|
||||||
boolean error = false;
|
|
||||||
if (parameters.length != 2) {
|
|
||||||
commandSystemWarning(() -> "The method '" + method.toString() + "' is lacking parameters or has too many");
|
|
||||||
error = true;
|
|
||||||
}
|
|
||||||
if (!parameters[parameters.length - 1].isVarArgs()) {
|
|
||||||
commandSystemWarning(() -> "The method '" + method.toString() + "' is lacking the varArgs parameters as last Argument");
|
|
||||||
error = true;
|
|
||||||
}
|
|
||||||
if (parameters[parameters.length - 1].getType().getComponentType() != String.class) {
|
|
||||||
commandSystemWarning(() -> "The method '" + method.toString() + "' is lacking the varArgs parameters of type '" + String.class.getTypeName() + "' as last Argument");
|
|
||||||
error = true;
|
|
||||||
}
|
|
||||||
if (error) return;
|
|
||||||
commandHelpList.add(new SubCommand<>(this, method, anno.value(), new HashMap<>(), new HashMap<>(), true, null, anno.noTabComplete()));
|
|
||||||
});
|
|
||||||
|
|
||||||
add(Register.class, method, i -> i > 0, true, null, (anno, parameters) -> {
|
|
||||||
if (anno.help()) return;
|
|
||||||
for (int i = 1; i < parameters.length; i++) {
|
for (int i = 1; i < parameters.length; i++) {
|
||||||
Parameter parameter = parameters[i];
|
Parameter parameter = parameters[i];
|
||||||
Class<?> clazz = parameter.getType();
|
Class<?> clazz = parameter.getType();
|
||||||
if (parameter.isVarArgs() && i == parameters.length - 1) {
|
if (parameter.isVarArgs()) clazz = clazz.getComponentType();
|
||||||
clazz = parameter.getType().getComponentType();
|
|
||||||
}
|
|
||||||
Mapper mapper = parameter.getAnnotation(Mapper.class);
|
Mapper mapper = parameter.getAnnotation(Mapper.class);
|
||||||
if (clazz.isEnum() && mapper == null && !SWCommandUtils.getMAPPER_FUNCTIONS().containsKey(clazz.getTypeName())) {
|
if (clazz.isEnum() && mapper == null && !SWCommandUtils.getMAPPER_FUNCTIONS().containsKey(clazz.getTypeName())) {
|
||||||
continue;
|
continue;
|
||||||
@ -217,66 +152,103 @@ public abstract class AbstractSWCommand<T> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
commandList.add(new SubCommand<>(this, method, anno.value(), localTypeMapper, localValidators, false, anno.description(), anno.noTabComplete()));
|
commandList.add(new SubCommand<>(this, method, anno.value(), localTypeMapper, localValidators, anno.description(), anno.noTabComplete()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.commandList.sort((o1, o2) -> {
|
if (dependencyMap.containsKey(this.getClass())) {
|
||||||
int compare = Integer.compare(-o1.subCommand.length, -o2.subCommand.length);
|
dependencyMap.get(this.getClass()).forEach(abstractSWCommand -> {
|
||||||
if (compare != 0) {
|
abstractSWCommand.localTypeMapper.putAll((Map) localTypeMapper);
|
||||||
return compare;
|
abstractSWCommand.localValidators.putAll((Map) localValidators);
|
||||||
|
abstractSWCommand.initialisePartOf(this);
|
||||||
|
abstractSWCommand.initialize();
|
||||||
|
commandList.addAll((Collection) abstractSWCommand.commandList);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Collections.sort(commandList);
|
||||||
|
commandList.removeIf(subCommand -> {
|
||||||
|
if (subCommand.isHelp) {
|
||||||
|
helpCommandList.add(subCommand);
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return Integer.compare(o1.comparableValue, o2.comparableValue);
|
return false;
|
||||||
}
|
|
||||||
});
|
|
||||||
commandHelpList.sort((o1, o2) -> {
|
|
||||||
int compare = Integer.compare(-o1.subCommand.length, -o2.subCommand.length);
|
|
||||||
if (compare != 0) {
|
|
||||||
return compare;
|
|
||||||
} else {
|
|
||||||
return Integer.compare(o1.method.getDeclaringClass() == AbstractSWCommand.class ? 1 : 0,
|
|
||||||
o2.method.getDeclaringClass() == AbstractSWCommand.class ? 1 : 0);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
initialized = true;
|
initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends Annotation> void add(Class<T> annotation, Method method, IntPredicate parameterTester, boolean firstParameter, Class<?> returnType, BiConsumer<T, Parameter[]> consumer) {
|
private boolean validateMethod(Method method) {
|
||||||
|
if (!checkType(method.getAnnotations(), method.getReturnType(), false, annotation -> {
|
||||||
|
CommandMetaData.Method methodMetaData = annotation.annotationType().getAnnotation(CommandMetaData.Method.class);
|
||||||
|
if (methodMetaData == null) return (aClass, varArg) -> true;
|
||||||
|
if (method.getParameterCount() > methodMetaData.maxParameterCount() || method.getParameterCount() < methodMetaData.minParameterCount())
|
||||||
|
return (aClass, varArg) -> false;
|
||||||
|
return (aClass, varArg) -> {
|
||||||
|
Class<?>[] types = methodMetaData.value();
|
||||||
|
if (types == null) return true;
|
||||||
|
for (Class<?> type : types) {
|
||||||
|
if (type.isAssignableFrom(aClass)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
}, "The method '" + method + "'")) return false;
|
||||||
|
boolean valid = true;
|
||||||
|
for (Parameter parameter : method.getParameters()) {
|
||||||
|
if (!checkType(parameter.getAnnotations(), parameter.getType(), parameter.isVarArgs(), annotation -> {
|
||||||
|
CommandMetaData.Parameter parameterMetaData = annotation.annotationType().getAnnotation(CommandMetaData.Parameter.class);
|
||||||
|
if (parameterMetaData == null) return (aClass, varArg) -> true;
|
||||||
|
Class<?> handler = parameterMetaData.handler();
|
||||||
|
if (BiPredicate.class.isAssignableFrom(handler)) {
|
||||||
|
try {
|
||||||
|
return (BiPredicate<Class<?>, Boolean>) handler.getConstructor().newInstance();
|
||||||
|
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
|
||||||
|
NoSuchMethodException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (aClass, varArg) -> {
|
||||||
|
if (varArg) aClass = aClass.getComponentType();
|
||||||
|
Class<?>[] types = parameterMetaData.value();
|
||||||
|
if (types == null) return true;
|
||||||
|
for (Class<?> current : types) {
|
||||||
|
if (current.isAssignableFrom(aClass)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
}, "The parameter '" + parameter + "'")) valid = false;
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkType(Annotation[] annotations, Class<?> clazz, boolean varArg, Function<Annotation, BiPredicate<Class<?>, Boolean>> toApplicableTypes, String warning) {
|
||||||
|
boolean valid = true;
|
||||||
|
for (Annotation annotation : annotations) {
|
||||||
|
BiPredicate<Class<?>, Boolean> predicate = toApplicableTypes.apply(annotation);
|
||||||
|
if (!predicate.test(clazz, varArg)) {
|
||||||
|
commandSystemWarning(() -> warning + " is using an unsupported annotation of type '" + annotation.annotationType().getName() + "'");
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends Annotation> void add(Class<T> annotation, Method method, boolean firstParameter, BiConsumer<T, Parameter[]> consumer) {
|
||||||
T[] anno = SWCommandUtils.getAnnotation(method, annotation);
|
T[] anno = SWCommandUtils.getAnnotation(method, annotation);
|
||||||
if (anno == null || anno.length == 0) return;
|
if (anno == null || anno.length == 0) return;
|
||||||
|
|
||||||
Parameter[] parameters = method.getParameters();
|
Parameter[] parameters = method.getParameters();
|
||||||
if (!parameterTester.test(parameters.length)) {
|
|
||||||
commandSystemWarning(() -> "The method '" + method.toString() + "' is lacking parameters or has too many");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (firstParameter && !clazz.isAssignableFrom(parameters[0].getType())) {
|
if (firstParameter && !clazz.isAssignableFrom(parameters[0].getType())) {
|
||||||
commandSystemWarning(() -> "The method '" + method.toString() + "' is lacking the first parameter of type '" + clazz.getTypeName() + "'");
|
commandSystemWarning(() -> "The method '" + method.toString() + "' is lacking the first parameter of type '" + clazz.getTypeName() + "'");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (returnType != null && !returnType.isAssignableFrom(method.getReturnType())) {
|
|
||||||
commandSystemWarning(() -> "The method '" + method.toString() + "' is lacking the desired return type '" + returnType.getTypeName() + "'");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Arrays.stream(anno).forEach(t -> consumer.accept(t, parameters));
|
Arrays.stream(anno).forEach(t -> consumer.accept(t, parameters));
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends Annotation> void addMapper(Class<T> annotation, Method method, IntPredicate parameterTester, boolean firstParameter, Class<?> returnType, BiConsumer<T, AbstractTypeMapper<?, ?>> consumer) {
|
private <T extends Annotation, K> void add(Class<T> annotation, Method method, BiConsumer<T, K> consumer) {
|
||||||
add(annotation, method, parameterTester, firstParameter, returnType, (anno, parameters) -> {
|
add(annotation, method, false, (anno, parameters) -> {
|
||||||
try {
|
try {
|
||||||
method.setAccessible(true);
|
method.setAccessible(true);
|
||||||
consumer.accept(anno, (AbstractTypeMapper<T, ?>) method.invoke(this));
|
consumer.accept(anno, (K) method.invoke(this));
|
||||||
} catch (Exception e) {
|
|
||||||
throw new SecurityException(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T extends Annotation> void addValidator(Class<T> annotation, Method method, IntPredicate parameterTester, boolean firstParameter, Class<?> returnType, BiConsumer<T, AbstractValidator<T, ?>> consumer) {
|
|
||||||
add(annotation, method, parameterTester, firstParameter, returnType, (anno, parameters) -> {
|
|
||||||
try {
|
|
||||||
method.setAccessible(true);
|
|
||||||
consumer.accept(anno, (AbstractValidator<T, ?>) method.invoke(this));
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new SecurityException(e.getMessage(), e);
|
throw new SecurityException(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
@ -300,12 +272,29 @@ public abstract class AbstractSWCommand<T> {
|
|||||||
return methods;
|
return methods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target({ElementType.TYPE})
|
||||||
|
public @interface PartOf {
|
||||||
|
Class<?> value();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Annotation for the command ---
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Annotation for registering a method as a command
|
||||||
|
*/
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target({ElementType.METHOD})
|
@Target({ElementType.METHOD})
|
||||||
@Repeatable(Register.Registeres.class)
|
@Repeatable(Register.Registeres.class)
|
||||||
|
@CommandMetaData.Method(value = void.class, minParameterCount = 1)
|
||||||
protected @interface Register {
|
protected @interface Register {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifier of subcommand
|
||||||
|
*/
|
||||||
String[] value() default {};
|
String[] value() default {};
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
boolean help() default false;
|
boolean help() default false;
|
||||||
|
|
||||||
String[] description() default {};
|
String[] description() default {};
|
||||||
@ -314,6 +303,7 @@ public abstract class AbstractSWCommand<T> {
|
|||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target({ElementType.METHOD})
|
@Target({ElementType.METHOD})
|
||||||
|
@CommandMetaData.Method(value = void.class, minParameterCount = 1)
|
||||||
@interface Registeres {
|
@interface Registeres {
|
||||||
Register[] value();
|
Register[] value();
|
||||||
}
|
}
|
||||||
@ -321,14 +311,41 @@ public abstract class AbstractSWCommand<T> {
|
|||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target({ElementType.PARAMETER, ElementType.METHOD})
|
@Target({ElementType.PARAMETER, ElementType.METHOD})
|
||||||
|
@CommandMetaData.Method(value = AbstractTypeMapper.class, maxParameterCount = 0)
|
||||||
|
@CommandMetaData.ImplicitTypeMapper(handler = Mapper.Handler.class)
|
||||||
protected @interface Mapper {
|
protected @interface Mapper {
|
||||||
String value();
|
String value();
|
||||||
|
|
||||||
boolean local() default false;
|
boolean local() default false;
|
||||||
|
|
||||||
|
class Handler<T> implements AbstractTypeMapper<T, Object> {
|
||||||
|
|
||||||
|
private AbstractTypeMapper<T, Object> inner;
|
||||||
|
|
||||||
|
public Handler(AbstractSWCommand.Mapper mapper, Map<String, AbstractTypeMapper<T, ?>> localTypeMapper) {
|
||||||
|
inner = (AbstractTypeMapper<T, Object>) SWCommandUtils.getTypeMapper(mapper.value(), localTypeMapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object map(T sender, PreviousArguments previousArguments, String s) {
|
||||||
|
return inner.map(sender, previousArguments, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean validate(T sender, Object value, MessageSender messageSender) {
|
||||||
|
return inner.validate(sender, value, messageSender);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<String> tabCompletes(T sender, PreviousArguments previousArguments, String s) {
|
||||||
|
return inner.tabCompletes(sender, previousArguments, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target({ElementType.METHOD})
|
@Target({ElementType.METHOD})
|
||||||
|
@CommandMetaData.Method(value = AbstractTypeMapper.class, maxParameterCount = 0)
|
||||||
protected @interface ClassMapper {
|
protected @interface ClassMapper {
|
||||||
Class<?> value();
|
Class<?> value();
|
||||||
|
|
||||||
@ -337,30 +354,58 @@ public abstract class AbstractSWCommand<T> {
|
|||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target({ElementType.METHOD})
|
@Target({ElementType.METHOD})
|
||||||
|
@CommandMetaData.Method(value = AbstractTypeMapper.class, maxParameterCount = 0)
|
||||||
protected @interface Cached {
|
protected @interface Cached {
|
||||||
long cacheDuration() default 5;
|
long cacheDuration() default 5;
|
||||||
|
|
||||||
TimeUnit timeUnit() default TimeUnit.SECONDS;
|
TimeUnit timeUnit() default TimeUnit.SECONDS;
|
||||||
|
|
||||||
boolean global() default false;
|
boolean global() default false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target({ElementType.PARAMETER, ElementType.METHOD})
|
@Target({ElementType.PARAMETER, ElementType.METHOD})
|
||||||
|
@CommandMetaData.Method(value = AbstractValidator.class, maxParameterCount = 0)
|
||||||
|
@CommandMetaData.ImplicitValidator(handler = Validator.Handler.class, order = 0)
|
||||||
protected @interface Validator {
|
protected @interface Validator {
|
||||||
String value() default "";
|
String value() default "";
|
||||||
|
|
||||||
boolean local() default false;
|
boolean local() default false;
|
||||||
|
|
||||||
|
boolean invert() default false;
|
||||||
|
|
||||||
|
class Handler<T> implements AbstractValidator<T, Object> {
|
||||||
|
|
||||||
|
private AbstractValidator<T, Object> inner;
|
||||||
|
private boolean invert;
|
||||||
|
|
||||||
|
public Handler(AbstractSWCommand.Validator validator, Class<?> clazz, Map<String, AbstractValidator<T, ?>> localValidator) {
|
||||||
|
inner = (AbstractValidator<T, Object>) SWCommandUtils.getValidator(validator, clazz, localValidator);
|
||||||
|
invert = validator.invert();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean validate(T sender, Object value, MessageSender messageSender) {
|
||||||
|
return inner.validate(sender, value, messageSender) ^ invert;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target({ElementType.METHOD})
|
@Target({ElementType.METHOD})
|
||||||
|
@CommandMetaData.Method(value = AbstractValidator.class, maxParameterCount = 0)
|
||||||
protected @interface ClassValidator {
|
protected @interface ClassValidator {
|
||||||
Class<?> value();
|
Class<?> value();
|
||||||
|
|
||||||
boolean local() default false;
|
boolean local() default false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Implicit TypeMapper ---
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target({ElementType.PARAMETER})
|
@Target({ElementType.PARAMETER})
|
||||||
|
@CommandMetaData.Parameter({String.class, int.class, Integer.class, long.class, Long.class, boolean.class, Boolean.class})
|
||||||
|
@CommandMetaData.ImplicitTypeMapper(handler = StaticValue.Handler.class)
|
||||||
protected @interface StaticValue {
|
protected @interface StaticValue {
|
||||||
String[] value();
|
String[] value();
|
||||||
|
|
||||||
@ -374,7 +419,49 @@ public abstract class AbstractSWCommand<T> {
|
|||||||
*/
|
*/
|
||||||
boolean allowISE() default false;
|
boolean allowISE() default false;
|
||||||
|
|
||||||
int[] falseValues() default { 0 };
|
int[] falseValues() default {0};
|
||||||
|
|
||||||
|
class Handler<T> implements AbstractTypeMapper<T, Object> {
|
||||||
|
|
||||||
|
private AbstractTypeMapper inner;
|
||||||
|
|
||||||
|
public Handler(StaticValue staticValue, Class<?> clazz) {
|
||||||
|
if (clazz == String.class) {
|
||||||
|
inner = SWCommandUtils.createMapper(staticValue.value());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!staticValue.allowISE()) {
|
||||||
|
throw new IllegalArgumentException("The parameter type '" + clazz.getTypeName() + "' is not supported by the StaticValue annotation");
|
||||||
|
}
|
||||||
|
if (clazz == boolean.class || clazz == Boolean.class) {
|
||||||
|
List<String> tabCompletes = new ArrayList<>(Arrays.asList(staticValue.value()));
|
||||||
|
Set<Integer> falseValues = new HashSet<>();
|
||||||
|
for (int i : staticValue.falseValues()) falseValues.add(i);
|
||||||
|
inner = SWCommandUtils.createMapper(s -> {
|
||||||
|
int index = tabCompletes.indexOf(s);
|
||||||
|
return index == -1 ? null : !falseValues.contains(index);
|
||||||
|
}, (commandSender, s) -> tabCompletes);
|
||||||
|
} else if (clazz == int.class || clazz == Integer.class || clazz == long.class || clazz == Long.class) {
|
||||||
|
List<String> tabCompletes = new ArrayList<>(Arrays.asList(staticValue.value()));
|
||||||
|
inner = SWCommandUtils.createMapper(s -> {
|
||||||
|
Number index = tabCompletes.indexOf(s);
|
||||||
|
return index.longValue() == -1 ? null : index;
|
||||||
|
}, (commandSender, s) -> tabCompletes);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("The parameter type '" + clazz.getTypeName() + "' is not supported by the StaticValue annotation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object map(T sender, PreviousArguments previousArguments, String s) {
|
||||||
|
return inner.map(sender, previousArguments, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<String> tabCompletes(T sender, PreviousArguments previousArguments, String s) {
|
||||||
|
return inner.tabCompletes(sender, previousArguments, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@ -391,8 +478,11 @@ public abstract class AbstractSWCommand<T> {
|
|||||||
boolean onlyUINIG() default false;
|
boolean onlyUINIG() default false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Implicit Validator ---
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target({ElementType.PARAMETER})
|
@Target({ElementType.PARAMETER})
|
||||||
|
@CommandMetaData.ImplicitValidator(handler = ErrorMessage.Handler.class, order = Integer.MAX_VALUE)
|
||||||
protected @interface ErrorMessage {
|
protected @interface ErrorMessage {
|
||||||
/**
|
/**
|
||||||
* Error message to be displayed when the parameter is invalid.
|
* Error message to be displayed when the parameter is invalid.
|
||||||
@ -403,6 +493,25 @@ public abstract class AbstractSWCommand<T> {
|
|||||||
* This is the short form for 'allowEmptyArrays'.
|
* This is the short form for 'allowEmptyArrays'.
|
||||||
*/
|
*/
|
||||||
boolean allowEAs() default true;
|
boolean allowEAs() default true;
|
||||||
|
|
||||||
|
class Handler<T> implements AbstractValidator<T, Object> {
|
||||||
|
|
||||||
|
private AbstractSWCommand.ErrorMessage errorMessage;
|
||||||
|
|
||||||
|
public Handler(AbstractSWCommand.ErrorMessage errorMessage) {
|
||||||
|
this.errorMessage = errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean validate(T sender, Object value, MessageSender messageSender) {
|
||||||
|
if (value == null) messageSender.send(errorMessage.value());
|
||||||
|
if (!errorMessage.allowEAs() && value != null && value.getClass().isArray() && Array.getLength(value) == 0) {
|
||||||
|
messageSender.send(errorMessage.value());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return value != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@ -410,11 +519,193 @@ public abstract class AbstractSWCommand<T> {
|
|||||||
protected @interface AllowNull {
|
protected @interface AllowNull {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This annotation is used to mark a String to be quotable with multiple words.
|
|
||||||
*/
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target({ElementType.PARAMETER})
|
@Target({ElementType.PARAMETER})
|
||||||
protected @interface Quotable {
|
@CommandMetaData.Parameter({int.class, Integer.class, long.class, Long.class, float.class, Float.class, double.class, Double.class})
|
||||||
|
@CommandMetaData.ImplicitValidator(handler = Min.Handler.class, order = 2)
|
||||||
|
protected @interface Min {
|
||||||
|
int intValue() default Integer.MIN_VALUE;
|
||||||
|
|
||||||
|
long longValue() default Long.MIN_VALUE;
|
||||||
|
|
||||||
|
float floatValue() default Float.MIN_VALUE;
|
||||||
|
|
||||||
|
double doubleValue() default Double.MIN_VALUE;
|
||||||
|
|
||||||
|
boolean inclusive() default true;
|
||||||
|
|
||||||
|
class Handler<T> implements AbstractValidator<T, Number> {
|
||||||
|
|
||||||
|
private int value;
|
||||||
|
private Function<Number, Number> comparator;
|
||||||
|
|
||||||
|
public Handler(AbstractSWCommand.Min min, Class<?> clazz) {
|
||||||
|
this.value = min.inclusive() ? 0 : 1;
|
||||||
|
this.comparator = createComparator("Min", clazz, min.intValue(), min.longValue(), min.floatValue(), min.doubleValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean validate(T sender, Number value, MessageSender messageSender) {
|
||||||
|
if (value == null) return true;
|
||||||
|
return (comparator.apply(value).intValue()) >= this.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target({ElementType.PARAMETER})
|
||||||
|
@CommandMetaData.Parameter({int.class, Integer.class, long.class, Long.class, float.class, Float.class, double.class, Double.class})
|
||||||
|
@CommandMetaData.ImplicitValidator(handler = Max.Handler.class, order = 2)
|
||||||
|
protected @interface Max {
|
||||||
|
int intValue() default Integer.MAX_VALUE;
|
||||||
|
|
||||||
|
long longValue() default Long.MAX_VALUE;
|
||||||
|
|
||||||
|
float floatValue() default Float.MAX_VALUE;
|
||||||
|
|
||||||
|
double doubleValue() default Double.MAX_VALUE;
|
||||||
|
|
||||||
|
boolean inclusive() default true;
|
||||||
|
|
||||||
|
class Handler<T> implements AbstractValidator<T, Number> {
|
||||||
|
|
||||||
|
private int value;
|
||||||
|
private Function<Number, Number> comparator;
|
||||||
|
|
||||||
|
public Handler(AbstractSWCommand.Max max, Class<?> clazz) {
|
||||||
|
this.value = max.inclusive() ? 0 : -1;
|
||||||
|
this.comparator = createComparator("Max", clazz, max.intValue(), max.longValue(), max.floatValue(), max.doubleValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean validate(T sender, Number value, MessageSender messageSender) {
|
||||||
|
if (value == null) return true;
|
||||||
|
return (comparator.apply(value).intValue()) <= this.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Function<Number, Number> createComparator(String type, Class<?> clazz, int iValue, long lValue, float fValue, double dValue) {
|
||||||
|
if (clazz == int.class || clazz == Integer.class) {
|
||||||
|
return number -> Integer.compare(number.intValue(), iValue);
|
||||||
|
} else if (clazz == long.class || clazz == Long.class) {
|
||||||
|
return number -> Long.compare(number.longValue(), lValue);
|
||||||
|
} else if (clazz == float.class || clazz == Float.class) {
|
||||||
|
return number -> Float.compare(number.floatValue(), fValue);
|
||||||
|
} else if (clazz == double.class || clazz == Double.class) {
|
||||||
|
return number -> Double.compare(number.doubleValue(), dValue);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException(type + " annotation is not supported for " + clazz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target({ElementType.PARAMETER})
|
||||||
|
@CommandMetaData.ImplicitTypeMapper(handler = Length.Handler.class)
|
||||||
|
protected @interface Length {
|
||||||
|
int min() default 0;
|
||||||
|
|
||||||
|
int max() default Integer.MAX_VALUE;
|
||||||
|
|
||||||
|
class Handler<T> implements AbstractTypeMapper<T, Object> {
|
||||||
|
|
||||||
|
private int min;
|
||||||
|
private int max;
|
||||||
|
private AbstractTypeMapper<T, Object> inner;
|
||||||
|
|
||||||
|
public Handler(Length length, AbstractTypeMapper<T, Object> inner) {
|
||||||
|
this.min = length.min();
|
||||||
|
this.max = length.max();
|
||||||
|
this.inner = inner;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object map(T sender, PreviousArguments previousArguments, String s) {
|
||||||
|
if (s.length() < min || s.length() > max) return null;
|
||||||
|
return inner.map(sender, previousArguments, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<String> tabCompletes(T sender, PreviousArguments previousArguments, String s) {
|
||||||
|
List<String> tabCompletes = inner.tabCompletes(sender, previousArguments, s)
|
||||||
|
.stream()
|
||||||
|
.filter(str -> str.length() >= min)
|
||||||
|
.map(str -> str.substring(0, Math.min(str.length(), max)))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (s.length() < min) {
|
||||||
|
tabCompletes.add(0, s);
|
||||||
|
}
|
||||||
|
return tabCompletes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String normalize(T sender, String s) {
|
||||||
|
return inner.normalize(sender, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target({ElementType.PARAMETER})
|
||||||
|
@CommandMetaData.Parameter(handler = ArrayLength.Type.class)
|
||||||
|
@CommandMetaData.ImplicitTypeMapper(handler = ArrayLength.HandlerTypeMapper.class)
|
||||||
|
@CommandMetaData.ImplicitValidator(handler = ArrayLength.HandlerValidator.class, order = 1)
|
||||||
|
protected @interface ArrayLength {
|
||||||
|
int min() default 0;
|
||||||
|
|
||||||
|
int max() default Integer.MAX_VALUE;
|
||||||
|
|
||||||
|
class Type implements BiPredicate<Class<?>, Boolean> {
|
||||||
|
@Override
|
||||||
|
public boolean test(Class<?> clazz, Boolean isVarArgs) {
|
||||||
|
return clazz.isArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class HandlerTypeMapper<T> implements AbstractTypeMapper<T, Object> {
|
||||||
|
|
||||||
|
private int max;
|
||||||
|
private AbstractTypeMapper<T, Object> inner;
|
||||||
|
|
||||||
|
public HandlerTypeMapper(ArrayLength arrayLength, AbstractTypeMapper<T, Object> inner) {
|
||||||
|
this.max = arrayLength.max();
|
||||||
|
this.inner = inner;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object map(T sender, PreviousArguments previousArguments, String s) {
|
||||||
|
return inner.map(sender, previousArguments, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<String> tabCompletes(T sender, PreviousArguments previousArguments, String s) {
|
||||||
|
Object[] mapped = previousArguments.getMappedArg(0);
|
||||||
|
if (mapped.length >= max) return Collections.emptyList();
|
||||||
|
return inner.tabCompletes(sender, previousArguments, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String normalize(T sender, String s) {
|
||||||
|
return inner.normalize(sender, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class HandlerValidator<T> implements AbstractValidator<T, Object> {
|
||||||
|
|
||||||
|
private int min;
|
||||||
|
private int max;
|
||||||
|
|
||||||
|
public HandlerValidator(ArrayLength arrayLength) {
|
||||||
|
this.min = arrayLength.min();
|
||||||
|
this.max = arrayLength.max();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean validate(T sender, Object value, MessageSender messageSender) {
|
||||||
|
if (value == null) return true;
|
||||||
|
int length = Array.getLength(value);
|
||||||
|
return length >= min && length <= max;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,12 +25,38 @@ public interface AbstractTypeMapper<K, T> extends AbstractValidator<K, T> {
|
|||||||
/**
|
/**
|
||||||
* The CommandSender can be null!
|
* The CommandSender can be null!
|
||||||
*/
|
*/
|
||||||
T map(K sender, String[] previousArguments, String s);
|
@Deprecated
|
||||||
|
default T map(K sender, String[] previousArguments, String s) {
|
||||||
|
throw new IllegalArgumentException("This method is deprecated and should not be used anymore!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The CommandSender can be null!
|
||||||
|
*/
|
||||||
|
default T map(K sender, PreviousArguments previousArguments, String s) {
|
||||||
|
return map(sender, previousArguments.userArgs, s);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default boolean validate(K sender, T value, MessageSender messageSender) {
|
default boolean validate(K sender, T value, MessageSender messageSender) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection<String> tabCompletes(K sender, String[] previousArguments, String s);
|
@Deprecated
|
||||||
|
default Collection<String> tabCompletes(K sender, String[] previousArguments, String s) {
|
||||||
|
throw new IllegalArgumentException("This method is deprecated and should not be used anymore!");
|
||||||
|
}
|
||||||
|
|
||||||
|
default Collection<String> tabCompletes(K sender, PreviousArguments previousArguments, String s) {
|
||||||
|
return tabCompletes(sender, previousArguments.userArgs, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize the cache key by sender and user provided argument. <br>
|
||||||
|
* Note: The CommandSender can be null! <br>
|
||||||
|
* Returning null and the empty string are equivalent.
|
||||||
|
*/
|
||||||
|
default String normalize(K sender, String s) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,10 +38,12 @@ public interface AbstractValidator<K, T> {
|
|||||||
*/
|
*/
|
||||||
boolean validate(K sender, T value, MessageSender messageSender);
|
boolean validate(K sender, T value, MessageSender messageSender);
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
default <C> Validator<C> validate(C value, MessageSender messageSender) {
|
default <C> Validator<C> validate(C value, MessageSender messageSender) {
|
||||||
return new Validator<>(value, messageSender);
|
return new Validator<>(value, messageSender);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
class Validator<C> {
|
class Validator<C> {
|
||||||
private final C value;
|
private final C value;
|
||||||
|
@ -36,12 +36,6 @@ public class CommandFrameworkException extends RuntimeException {
|
|||||||
|
|
||||||
private String message;
|
private String message;
|
||||||
|
|
||||||
static CommandFrameworkException commandGetExceptions(String type, Class<?> clazzType, Executable executable, int index) {
|
|
||||||
return new CommandFrameworkException(throwable -> {
|
|
||||||
return CommandFrameworkException.class.getTypeName() + ": Error while getting " + type + " for " + clazzType.getTypeName() + " with parameter index " + index;
|
|
||||||
}, null, throwable -> Stream.empty(), executable.getDeclaringClass().getTypeName() + "." + executable.getName() + "(Unknown Source)");
|
|
||||||
}
|
|
||||||
|
|
||||||
static CommandFrameworkException commandPartExceptions(String type, Throwable cause, String current, Class<?> clazzType, Executable executable, int index) {
|
static CommandFrameworkException commandPartExceptions(String type, Throwable cause, String current, Class<?> clazzType, Executable executable, int index) {
|
||||||
return new CommandFrameworkException(e -> {
|
return new CommandFrameworkException(e -> {
|
||||||
return CommandFrameworkException.class.getTypeName() + ": Error while " + type + " (" + current + ") to type " + clazzType.getTypeName() + " with parameter index " + index;
|
return CommandFrameworkException.class.getTypeName() + ": Error while " + type + " (" + current + ") to type " + clazzType.getTypeName() + " with parameter index " + index;
|
||||||
|
92
src/de/steamwar/command/CommandMetaData.java
Normale Datei
92
src/de/steamwar/command/CommandMetaData.java
Normale Datei
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.command;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
public @interface CommandMetaData {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This annotation is only for internal use.
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.ANNOTATION_TYPE)
|
||||||
|
@interface Method {
|
||||||
|
Class<?>[] value();
|
||||||
|
int minParameterCount() default 0;
|
||||||
|
int maxParameterCount() default Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This annotation denotes what types are allowed as parameter types the annotation annotated with can use.
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.ANNOTATION_TYPE)
|
||||||
|
@interface Parameter {
|
||||||
|
Class<?>[] value() default {};
|
||||||
|
Class<?> handler() default void.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This annotation can be used in conjunction with a class that implements {@link AbstractTypeMapper} to
|
||||||
|
* create a custom type mapper for a parameter. The class must have one of two constructors with the following
|
||||||
|
* types:
|
||||||
|
* <ul>
|
||||||
|
* <li>Annotation this annotation annotates</li>
|
||||||
|
* <li>{@link Class}</li>
|
||||||
|
* <li>{@link AbstractTypeMapper}, optional, if not present only one per parameter</li>
|
||||||
|
* <li>{@link java.util.Map} with types {@link String} and {@link AbstractValidator}</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.ANNOTATION_TYPE)
|
||||||
|
@interface ImplicitTypeMapper {
|
||||||
|
/**
|
||||||
|
* The validator class that should be used.
|
||||||
|
*/
|
||||||
|
Class<?> handler();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This annotation can be used in conjunction with a class that implements {@link AbstractValidator} to
|
||||||
|
* create a custom validator short hands for commands. The validator class must have one constructor with
|
||||||
|
* one of the following types:
|
||||||
|
* <ul>
|
||||||
|
* <li>Annotation this annotation annotates</li>
|
||||||
|
* <li>{@link Class}</li>
|
||||||
|
* <li>{@link java.util.Map} with types {@link String} and {@link AbstractValidator}</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.ANNOTATION_TYPE)
|
||||||
|
@interface ImplicitValidator {
|
||||||
|
/**
|
||||||
|
* The validator class that should be used.
|
||||||
|
*/
|
||||||
|
Class<?> handler();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines when this validator should be processed. Negative numbers denote that this will be
|
||||||
|
* processed before {@link AbstractSWCommand.Validator} and positive numbers
|
||||||
|
* denote that this will be processed after {@link AbstractSWCommand.Validator}.
|
||||||
|
*/
|
||||||
|
int order();
|
||||||
|
}
|
||||||
|
}
|
@ -24,6 +24,7 @@ import lombok.Setter;
|
|||||||
|
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.lang.reflect.Parameter;
|
import java.lang.reflect.Parameter;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -31,7 +32,8 @@ import java.util.function.Consumer;
|
|||||||
|
|
||||||
class CommandPart<T> {
|
class CommandPart<T> {
|
||||||
|
|
||||||
private static final String[] EMPTY_ARRAY = new String[0];
|
private static final String[] EMPTY_STRING_ARRAY = new String[0];
|
||||||
|
private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
private static class CheckArgumentResult {
|
private static class CheckArgumentResult {
|
||||||
@ -41,7 +43,7 @@ class CommandPart<T> {
|
|||||||
|
|
||||||
private AbstractSWCommand<T> command;
|
private AbstractSWCommand<T> command;
|
||||||
private AbstractTypeMapper<T, ?> typeMapper;
|
private AbstractTypeMapper<T, ?> typeMapper;
|
||||||
private AbstractValidator<T, Object> validator;
|
private List<AbstractValidator<T, Object>> validators = new ArrayList<>();
|
||||||
private Class<?> varArgType;
|
private Class<?> varArgType;
|
||||||
private String optional;
|
private String optional;
|
||||||
|
|
||||||
@ -53,25 +55,25 @@ class CommandPart<T> {
|
|||||||
@Setter
|
@Setter
|
||||||
private boolean onlyUseIfNoneIsGiven = false;
|
private boolean onlyUseIfNoneIsGiven = false;
|
||||||
|
|
||||||
@Setter
|
|
||||||
private boolean allowNullValues = false;
|
|
||||||
|
|
||||||
@Setter
|
|
||||||
private boolean quotable = false;
|
|
||||||
|
|
||||||
private Parameter parameter;
|
private Parameter parameter;
|
||||||
private int parameterIndex;
|
private int parameterIndex;
|
||||||
|
|
||||||
public CommandPart(AbstractSWCommand<T> command, AbstractTypeMapper<T, ?> typeMapper, AbstractValidator<T, Object> validator, Class<?> varArgType, String optional, Parameter parameter, int parameterIndex) {
|
public CommandPart(AbstractSWCommand<T> command, AbstractTypeMapper<T, ?> typeMapper, Class<?> varArgType, String optional, Parameter parameter, int parameterIndex) {
|
||||||
this.command = command;
|
this.command = command;
|
||||||
this.typeMapper = typeMapper;
|
this.typeMapper = typeMapper;
|
||||||
this.validator = validator;
|
|
||||||
this.varArgType = varArgType;
|
this.varArgType = varArgType;
|
||||||
this.optional = optional;
|
this.optional = optional;
|
||||||
this.parameter = parameter;
|
this.parameter = parameter;
|
||||||
this.parameterIndex = parameterIndex;
|
this.parameterIndex = parameterIndex;
|
||||||
|
|
||||||
validatePart();
|
if (optional != null && varArgType != null) {
|
||||||
|
throw new IllegalArgumentException("A vararg part can't have an optional part! In method " + parameter.getDeclaringExecutable() + " with parameter " + parameterIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void addValidator(AbstractValidator<T, Object> validator) {
|
||||||
|
if (validator == null) return;
|
||||||
|
validators.add(validator);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNext(CommandPart<T> next) {
|
public void setNext(CommandPart<T> next) {
|
||||||
@ -81,9 +83,17 @@ class CommandPart<T> {
|
|||||||
this.next = next;
|
this.next = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validatePart() {
|
public boolean isHelp() {
|
||||||
if (optional != null && varArgType != null) {
|
if (next == null) {
|
||||||
throw new IllegalArgumentException("A vararg part can't have an optional part! In method " + parameter.getDeclaringExecutable() + " with parameter " + parameterIndex);
|
if (varArgType == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (varArgType != String.class) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return typeMapper == SWCommandUtils.STRING_MAPPER;
|
||||||
|
} else {
|
||||||
|
return next.isHelp();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,31 +101,29 @@ class CommandPart<T> {
|
|||||||
if (varArgType != null) {
|
if (varArgType != null) {
|
||||||
Object array = Array.newInstance(varArgType, args.length - startIndex);
|
Object array = Array.newInstance(varArgType, args.length - startIndex);
|
||||||
for (int i = startIndex; i < args.length; i++) {
|
for (int i = startIndex; i < args.length; i++) {
|
||||||
CheckArgumentResult validArgument = checkArgument(null, sender, args, i);
|
CheckArgumentResult validArgument = checkArgument(null, sender, args, current, i);
|
||||||
if (!validArgument.success) {
|
if (!validArgument.success) throw new CommandParseException();
|
||||||
throw new CommandParseException();
|
|
||||||
}
|
|
||||||
Array.set(array, i - startIndex, validArgument.value);
|
Array.set(array, i - startIndex, validArgument.value);
|
||||||
}
|
}
|
||||||
if (validator != null && !validator.validate(sender, array, (s, objects) -> {
|
for (AbstractValidator<T, Object> validator : validators) {
|
||||||
errors.accept(() -> command.sendMessage(sender, s, objects));
|
if (!validator.validate(sender, array, (s, objects) -> {
|
||||||
})) {
|
errors.accept(() -> command.sendMessage(sender, s, objects));
|
||||||
throw new CommandParseException();
|
})) throw new CommandParseException();
|
||||||
}
|
}
|
||||||
current.add(array);
|
current.add(array);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckArgumentResult validArgument = checkArgument(errors, sender, args, startIndex);
|
CheckArgumentResult validArgument = checkArgument(errors, sender, args, current, startIndex);
|
||||||
if (!validArgument.success && optional == null) {
|
if (!validArgument.success && optional == null) {
|
||||||
throw new CommandParseException();
|
throw new CommandParseException();
|
||||||
}
|
}
|
||||||
if (!validArgument.success) {
|
if (!validArgument.success) {
|
||||||
if (!ignoreAsArgument) {
|
if (!ignoreAsArgument) {
|
||||||
if (!onlyUseIfNoneIsGiven) {
|
if (!onlyUseIfNoneIsGiven) {
|
||||||
current.add(typeMapper.map(sender, EMPTY_ARRAY, optional));
|
current.add(typeMapper.map(sender, new PreviousArguments(EMPTY_STRING_ARRAY, EMPTY_OBJECT_ARRAY), optional));
|
||||||
} else if (startIndex >= args.length) {
|
} else if (startIndex >= args.length) {
|
||||||
current.add(typeMapper.map(sender, EMPTY_ARRAY, optional));
|
current.add(typeMapper.map(sender, new PreviousArguments(EMPTY_STRING_ARRAY, EMPTY_OBJECT_ARRAY), optional));
|
||||||
} else {
|
} else {
|
||||||
throw new CommandParseException();
|
throw new CommandParseException();
|
||||||
}
|
}
|
||||||
@ -130,18 +138,23 @@ class CommandPart<T> {
|
|||||||
}
|
}
|
||||||
if (next != null) {
|
if (next != null) {
|
||||||
next.generateArgumentArray(errors, current, sender, args, startIndex + 1);
|
next.generateArgumentArray(errors, current, sender, args, startIndex + 1);
|
||||||
|
} else if (startIndex + 1 < args.length) {
|
||||||
|
throw new CommandParseException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void generateTabComplete(List<String> current, T sender, String[] args, int startIndex) {
|
public void generateTabComplete(List<String> current, T sender, String[] args, List<Object> mappedArgs, int startIndex) {
|
||||||
if (varArgType != null) {
|
if (varArgType != null) {
|
||||||
|
List<Object> currentArgs = new ArrayList<>(mappedArgs);
|
||||||
|
List<Object> varArgs = new ArrayList<>();
|
||||||
for (int i = startIndex; i < args.length - 1; i++) {
|
for (int i = startIndex; i < args.length - 1; i++) {
|
||||||
CheckArgumentResult validArgument = checkArgument((ignore) -> {}, sender, args, i);
|
CheckArgumentResult validArgument = checkArgument((ignore) -> {}, sender, args, mappedArgs, i);
|
||||||
if (!validArgument.success) {
|
if (!validArgument.success) return;
|
||||||
return;
|
varArgs.add(validArgument.value);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Collection<String> strings = tabCompletes(sender, args, args.length - 1);
|
|
||||||
|
currentArgs.add(varArgs.toArray());
|
||||||
|
Collection<String> strings = tabCompletes(sender, args, currentArgs, args.length - 1);
|
||||||
if (strings != null) {
|
if (strings != null) {
|
||||||
current.addAll(strings);
|
current.addAll(strings);
|
||||||
}
|
}
|
||||||
@ -149,59 +162,65 @@ class CommandPart<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (args.length - 1 > startIndex) {
|
if (args.length - 1 > startIndex) {
|
||||||
CheckArgumentResult checkArgumentResult = checkArgument((ignore) -> {}, sender, args, startIndex);
|
CheckArgumentResult checkArgumentResult = checkArgument((ignore) -> {}, sender, args, mappedArgs, startIndex);
|
||||||
if (checkArgumentResult.success && next != null) {
|
if (checkArgumentResult.success && next != null) {
|
||||||
next.generateTabComplete(current, sender, args, startIndex + 1);
|
if (!ignoreAsArgument) {
|
||||||
|
mappedArgs.add(checkArgumentResult.value);
|
||||||
|
}
|
||||||
|
next.generateTabComplete(current, sender, args, mappedArgs, startIndex + 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (optional != null && next != null) {
|
if (optional != null && next != null) {
|
||||||
next.generateTabComplete(current, sender, args, startIndex);
|
next.generateTabComplete(current, sender, args, mappedArgs, startIndex);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection<String> strings = tabCompletes(sender, args, startIndex);
|
Collection<String> strings = tabCompletes(sender, args, mappedArgs, startIndex);
|
||||||
if (strings != null) {
|
if (strings != null) {
|
||||||
current.addAll(strings);
|
current.addAll(strings);
|
||||||
}
|
}
|
||||||
if (optional != null && next != null) {
|
if (optional != null && next != null) {
|
||||||
next.generateTabComplete(current, sender, args, startIndex);
|
next.generateTabComplete(current, sender, args, mappedArgs, startIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Collection<String> tabCompletes(T sender, String[] args, int startIndex) {
|
private Collection<String> tabCompletes(T sender, String[] args, List<Object> mappedArgs, int startIndex) {
|
||||||
return TabCompletionCache.tabComplete(sender, typeMapper, command, () -> {
|
return TabCompletionCache.tabComplete(sender, args[startIndex], (AbstractTypeMapper<Object, ?>) typeMapper, () -> {
|
||||||
try {
|
try {
|
||||||
return typeMapper.tabCompletes(sender, Arrays.copyOf(args, startIndex), args[startIndex]);
|
return typeMapper.tabCompletes(sender, new PreviousArguments(Arrays.copyOf(args, startIndex), mappedArgs.toArray()), args[startIndex]);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
throw CommandFrameworkException.commandPartExceptions("tabcompleting", e, args[startIndex], (varArgType != null ? varArgType : parameter.getType()), parameter.getDeclaringExecutable(), parameterIndex);
|
throw CommandFrameworkException.commandPartExceptions("tabcompleting", e, args[startIndex], (varArgType != null ? varArgType : parameter.getType()), parameter.getDeclaringExecutable(), parameterIndex);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private CheckArgumentResult checkArgument(Consumer<Runnable> errors, T sender, String[] args, int index) {
|
private CheckArgumentResult checkArgument(Consumer<Runnable> errors, T sender, String[] args, List<Object> mappedArgs, int index) {
|
||||||
Object value;
|
Object value;
|
||||||
try {
|
try {
|
||||||
value = typeMapper.map(sender, Arrays.copyOf(args, index), args[index]);
|
value = typeMapper.map(sender, new PreviousArguments(Arrays.copyOf(args, index), mappedArgs.toArray()), args[index]);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return new CheckArgumentResult(false, null);
|
return new CheckArgumentResult(false, null);
|
||||||
}
|
}
|
||||||
if (value instanceof String && !quotable && ((String) value).contains(" ")) {
|
boolean success = true;
|
||||||
return new CheckArgumentResult(false, null);
|
for (AbstractValidator<T, Object> validator : validators) {
|
||||||
}
|
|
||||||
if (validator != null && errors != null) {
|
|
||||||
try {
|
try {
|
||||||
if (!validator.validate(sender, value, (s, objects) -> {
|
if (!validator.validate(sender, value, (s, objects) -> {
|
||||||
errors.accept(() -> {
|
errors.accept(() -> {
|
||||||
command.sendMessage(sender, s, objects);
|
command.sendMessage(sender, s, objects);
|
||||||
});
|
});
|
||||||
})) {
|
})) {
|
||||||
return new CheckArgumentResult(false, null);
|
success = false;
|
||||||
|
value = null;
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
throw CommandFrameworkException.commandPartExceptions("validating", e, args[index], (varArgType != null ? varArgType : parameter.getType()), parameter.getDeclaringExecutable(), parameterIndex);
|
throw CommandFrameworkException.commandPartExceptions("validating", e, args[index], (varArgType != null ? varArgType : parameter.getType()), parameter.getDeclaringExecutable(), parameterIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new CheckArgumentResult(allowNullValues || value != null, value);
|
return new CheckArgumentResult(success, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<?> getType() {
|
||||||
|
return varArgType != null ? varArgType : parameter.getType();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
62
src/de/steamwar/command/PreviousArguments.java
Normale Datei
62
src/de/steamwar/command/PreviousArguments.java
Normale Datei
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.command;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class PreviousArguments {
|
||||||
|
|
||||||
|
public final String[] userArgs;
|
||||||
|
public final Object[] mappedArgs;
|
||||||
|
|
||||||
|
public PreviousArguments(String[] userArgs, Object[] mappedArgs) {
|
||||||
|
this.userArgs = userArgs;
|
||||||
|
this.mappedArgs = mappedArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserArg(int index) {
|
||||||
|
return userArgs[userArgs.length - index - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T getMappedArg(int index) {
|
||||||
|
return (T) mappedArgs[mappedArgs.length - index - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> Optional<T> getFirst(Class<T> clazz) {
|
||||||
|
for (Object o : mappedArgs) {
|
||||||
|
if (clazz.isInstance(o)) {
|
||||||
|
return Optional.of((T) o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> List<T> getAll(Class<T> clazz) {
|
||||||
|
List<T> list = new ArrayList<>();
|
||||||
|
for (Object o : mappedArgs) {
|
||||||
|
if (clazz.isInstance(o)) {
|
||||||
|
list.add((T) o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
@ -23,7 +23,6 @@ import lombok.Getter;
|
|||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Array;
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Parameter;
|
import java.lang.reflect.Parameter;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@ -42,16 +41,18 @@ public class SWCommandUtils {
|
|||||||
|
|
||||||
private SWTypeMapperCreator swTypeMapperCreator = (mapper, tabCompleter) -> new AbstractTypeMapper<Object, Object>() {
|
private SWTypeMapperCreator swTypeMapperCreator = (mapper, tabCompleter) -> new AbstractTypeMapper<Object, Object>() {
|
||||||
@Override
|
@Override
|
||||||
public Object map(Object sender, String[] previousArguments, String s) {
|
public Object map(Object sender, PreviousArguments previousArguments, String s) {
|
||||||
return mapper.apply(s);
|
return mapper.apply(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<String> tabCompletes(Object sender, String[] previousArguments, String s) {
|
public Collection<String> tabCompletes(Object sender, PreviousArguments previousArguments, String s) {
|
||||||
return ((BiFunction<Object, Object, Collection<String>>) tabCompleter).apply(sender, s);
|
return ((BiFunction<Object, Object, Collection<String>>) tabCompleter).apply(sender, s);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static final AbstractTypeMapper<Object, String> STRING_MAPPER = createMapper(s -> s, Collections::singletonList);
|
||||||
|
|
||||||
static {
|
static {
|
||||||
addMapper(boolean.class, Boolean.class, createMapper(s -> {
|
addMapper(boolean.class, Boolean.class, createMapper(s -> {
|
||||||
if (s.equalsIgnoreCase("true")) return true;
|
if (s.equalsIgnoreCase("true")) return true;
|
||||||
@ -62,15 +63,7 @@ public class SWCommandUtils {
|
|||||||
addMapper(double.class, Double.class, createMapper(numberMapper(Double::parseDouble), numberCompleter(Double::parseDouble, true)));
|
addMapper(double.class, Double.class, createMapper(numberMapper(Double::parseDouble), numberCompleter(Double::parseDouble, true)));
|
||||||
addMapper(int.class, Integer.class, createMapper(numberMapper(Integer::parseInt), numberCompleter(Integer::parseInt, false)));
|
addMapper(int.class, Integer.class, createMapper(numberMapper(Integer::parseInt), numberCompleter(Integer::parseInt, false)));
|
||||||
addMapper(long.class, Long.class, createMapper(numberMapper(Long::parseLong), numberCompleter(Long::parseLong, false)));
|
addMapper(long.class, Long.class, createMapper(numberMapper(Long::parseLong), numberCompleter(Long::parseLong, false)));
|
||||||
MAPPER_FUNCTIONS.put(String.class.getTypeName(), createMapper(s -> {
|
MAPPER_FUNCTIONS.put(String.class.getTypeName(), STRING_MAPPER);
|
||||||
if (s.startsWith("\"") && s.endsWith("\"")) {
|
|
||||||
return s.substring(1, s.length() - 1);
|
|
||||||
}
|
|
||||||
if (s.startsWith("'") && s.endsWith("'")) {
|
|
||||||
return s.substring(1, s.length() - 1);
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}, Collections::singletonList));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends AbstractTypeMapper<K, V>, K, V> void init(SWTypeMapperCreator<T, K, V> swTypeMapperCreator) {
|
public static <T extends AbstractTypeMapper<K, V>, K, V> void init(SWTypeMapperCreator<T, K, V> swTypeMapperCreator) {
|
||||||
@ -82,87 +75,7 @@ public class SWCommandUtils {
|
|||||||
MAPPER_FUNCTIONS.put(alternativeClazz.getTypeName(), mapper);
|
MAPPER_FUNCTIONS.put(alternativeClazz.getTypeName(), mapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
static <T> CommandPart<T> generateCommandPart(AbstractSWCommand<T> command, boolean help, String[] subCommand, Parameter[] parameters, Map<String, AbstractTypeMapper<T, ?>> localTypeMapper, Map<String, AbstractValidator<T, ?>> localValidator) {
|
public static <T> AbstractTypeMapper<T, ?> getTypeMapper(String name, Map<String, AbstractTypeMapper<T, ?>> localTypeMapper) {
|
||||||
CommandPart<T> first = null;
|
|
||||||
CommandPart<T> current = null;
|
|
||||||
for (String s : subCommand) {
|
|
||||||
CommandPart commandPart = new CommandPart(command, createMapper(s), null, null, null, null, -1);
|
|
||||||
commandPart.setIgnoreAsArgument(true);
|
|
||||||
if (current != null) {
|
|
||||||
current.setNext(commandPart);
|
|
||||||
}
|
|
||||||
current = commandPart;
|
|
||||||
if (first == null) {
|
|
||||||
first = current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int i = 1; i < parameters.length; i++) {
|
|
||||||
Parameter parameter = parameters[i];
|
|
||||||
AbstractTypeMapper<T, ?> typeMapper = getTypeMapper(parameter, localTypeMapper);
|
|
||||||
AbstractValidator<T, Object> validator = (AbstractValidator<T, Object>) getValidator(parameter, localValidator);
|
|
||||||
Class<?> varArgType = parameter.isVarArgs() ? parameter.getType().getComponentType() : null;
|
|
||||||
AbstractSWCommand.OptionalValue optionalValue = parameter.getAnnotation(AbstractSWCommand.OptionalValue.class);
|
|
||||||
AbstractSWCommand.AllowNull allowNull = parameter.getAnnotation(AbstractSWCommand.AllowNull.class);
|
|
||||||
AbstractSWCommand.Quotable quotable = parameter.getAnnotation(AbstractSWCommand.Quotable.class);
|
|
||||||
|
|
||||||
CommandPart<T> commandPart = new CommandPart<>(command, typeMapper, validator, varArgType, optionalValue != null ? optionalValue.value() : null, parameter, i);
|
|
||||||
commandPart.setOnlyUseIfNoneIsGiven(optionalValue != null && optionalValue.onlyUINIG());
|
|
||||||
commandPart.setAllowNullValues(allowNull != null);
|
|
||||||
commandPart.setQuotable(quotable != null);
|
|
||||||
if (current != null) {
|
|
||||||
current.setNext(commandPart);
|
|
||||||
}
|
|
||||||
current = commandPart;
|
|
||||||
if (first == null) {
|
|
||||||
first = current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return first;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> AbstractTypeMapper<T, ?> getTypeMapper(Parameter parameter, Map<String, AbstractTypeMapper<T, ?>> localTypeMapper) {
|
|
||||||
Class<?> clazz = parameter.getType();
|
|
||||||
if (parameter.isVarArgs()) {
|
|
||||||
clazz = clazz.getComponentType();
|
|
||||||
}
|
|
||||||
|
|
||||||
AbstractSWCommand.ClassMapper classMapper = parameter.getAnnotation(AbstractSWCommand.ClassMapper.class);
|
|
||||||
AbstractSWCommand.Mapper mapper = parameter.getAnnotation(AbstractSWCommand.Mapper.class);
|
|
||||||
if (clazz.isEnum() && classMapper == null && mapper == null && !MAPPER_FUNCTIONS.containsKey(clazz.getTypeName()) && !localTypeMapper.containsKey(clazz.getTypeName())) {
|
|
||||||
return createEnumMapper((Class<Enum<?>>) clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
String name = clazz.getTypeName();
|
|
||||||
if (classMapper != null) {
|
|
||||||
name = classMapper.value().getTypeName();
|
|
||||||
} else if (mapper != null) {
|
|
||||||
name = mapper.value();
|
|
||||||
} else {
|
|
||||||
AbstractSWCommand.StaticValue staticValue = parameter.getAnnotation(AbstractSWCommand.StaticValue.class);
|
|
||||||
if (staticValue != null) {
|
|
||||||
if (parameter.getType() == String.class) {
|
|
||||||
return createMapper(staticValue.value());
|
|
||||||
}
|
|
||||||
if (staticValue.allowISE()) {
|
|
||||||
if ((parameter.getType() == boolean.class || parameter.getType() == Boolean.class)) {
|
|
||||||
List<String> tabCompletes = new ArrayList<>(Arrays.asList(staticValue.value()));
|
|
||||||
Set<Integer> falseValues = new HashSet<>();
|
|
||||||
for (int i : staticValue.falseValues()) falseValues.add(i);
|
|
||||||
return createMapper(s -> {
|
|
||||||
int index = tabCompletes.indexOf(s);
|
|
||||||
return index == -1 ? null : !falseValues.contains(index);
|
|
||||||
}, (commandSender, s) -> tabCompletes);
|
|
||||||
}
|
|
||||||
if ((parameter.getType() == int.class || parameter.getType() == Integer.class || parameter.getType() == long.class || parameter.getType() == Long.class) && staticValue.value().length >= 2) {
|
|
||||||
List<String> tabCompletes = new ArrayList<>(Arrays.asList(staticValue.value()));
|
|
||||||
return createMapper(s -> {
|
|
||||||
Number index = tabCompletes.indexOf(s);
|
|
||||||
return index.longValue() == -1 ? null : index;
|
|
||||||
}, (commandSender, s) -> tabCompletes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AbstractTypeMapper<T, ?> typeMapper = localTypeMapper.getOrDefault(name, (AbstractTypeMapper<T, ?>) MAPPER_FUNCTIONS.getOrDefault(name, null));
|
AbstractTypeMapper<T, ?> typeMapper = localTypeMapper.getOrDefault(name, (AbstractTypeMapper<T, ?>) MAPPER_FUNCTIONS.getOrDefault(name, null));
|
||||||
if (typeMapper == null) {
|
if (typeMapper == null) {
|
||||||
throw new IllegalArgumentException("No mapper found for " + name);
|
throw new IllegalArgumentException("No mapper found for " + name);
|
||||||
@ -170,45 +83,24 @@ public class SWCommandUtils {
|
|||||||
return typeMapper;
|
return typeMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> AbstractValidator<T, ?> getValidator(Parameter parameter, Map<String, AbstractValidator<T, ?>> localValidator) {
|
public static <T> AbstractTypeMapper<T, ?> getTypeMapper(Parameter parameter, Map<String, AbstractTypeMapper<T, ?>> localTypeMapper) {
|
||||||
Class<?> clazz = parameter.getType();
|
Class<?> clazz = parameter.getType();
|
||||||
|
if (parameter.isVarArgs()) {
|
||||||
AbstractSWCommand.ClassValidator classValidator = parameter.getAnnotation(AbstractSWCommand.ClassValidator.class);
|
clazz = clazz.getComponentType();
|
||||||
if (classValidator != null) {
|
|
||||||
if (classValidator.value() != null) {
|
|
||||||
return getValidator(classValidator.value().getTypeName(), localValidator);
|
|
||||||
}
|
|
||||||
return getValidator(clazz.getTypeName(), localValidator);
|
|
||||||
}
|
}
|
||||||
|
if (clazz.isEnum() && !MAPPER_FUNCTIONS.containsKey(clazz.getTypeName()) && !localTypeMapper.containsKey(clazz.getTypeName())) {
|
||||||
AbstractSWCommand.Validator validator = parameter.getAnnotation(AbstractSWCommand.Validator.class);
|
return createEnumMapper((Class<Enum<?>>) clazz);
|
||||||
if (validator != null) {
|
|
||||||
if (validator.value() != null && !validator.value().isEmpty()) {
|
|
||||||
return getValidator(validator.value(), localValidator);
|
|
||||||
}
|
|
||||||
return getValidator(clazz.getTypeName(), localValidator);
|
|
||||||
}
|
}
|
||||||
|
return getTypeMapper(clazz.getTypeName(), localTypeMapper);
|
||||||
AbstractSWCommand.ErrorMessage errorMessage = parameter.getAnnotation(AbstractSWCommand.ErrorMessage.class);
|
|
||||||
if (errorMessage != null) {
|
|
||||||
return (AbstractValidator<T, Object>) (sender, value, messageSender) -> {
|
|
||||||
if (value == null) messageSender.send(errorMessage.value());
|
|
||||||
if (!errorMessage.allowEAs() && value != null && value.getClass().isArray() && Array.getLength(value) == 0) {
|
|
||||||
messageSender.send(errorMessage.value());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return value != null;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> AbstractValidator<T, ?> getValidator(String s, Map<String, AbstractValidator<T, ?>> localGuardChecker) {
|
public static <T> AbstractValidator<T, ?> getValidator(AbstractSWCommand.Validator validator, Class<?> type, Map<String, AbstractValidator<T, ?>> localValidator) {
|
||||||
AbstractValidator<T, ?> validator = localGuardChecker.getOrDefault(s, (AbstractValidator<T, ?>) VALIDATOR_FUNCTIONS.getOrDefault(s, null));
|
String s = validator.value() != null && !validator.value().isEmpty() ? validator.value() : type.getTypeName();
|
||||||
if (validator == null) {
|
AbstractValidator<T, ?> concreteValidator = localValidator.getOrDefault(s, (AbstractValidator<T, ?>) VALIDATOR_FUNCTIONS.getOrDefault(s, null));
|
||||||
|
if (concreteValidator == null) {
|
||||||
throw new IllegalArgumentException("No validator found for " + s);
|
throw new IllegalArgumentException("No validator found for " + s);
|
||||||
}
|
}
|
||||||
return validator;
|
return concreteValidator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <K, T> void addMapper(Class<T> clazz, AbstractTypeMapper<K, T> mapper) {
|
public static <K, T> void addMapper(Class<T> clazz, AbstractTypeMapper<K, T> mapper) {
|
||||||
|
@ -19,17 +19,20 @@
|
|||||||
|
|
||||||
package de.steamwar.command;
|
package de.steamwar.command;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Parameter;
|
import java.lang.reflect.Parameter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
public class SubCommand<T> {
|
public class SubCommand<T> implements Comparable<SubCommand<T>> {
|
||||||
|
|
||||||
private AbstractSWCommand<T> abstractSWCommand;
|
private AbstractSWCommand<T> abstractSWCommand;
|
||||||
Method method;
|
Method method;
|
||||||
@ -39,11 +42,14 @@ public class SubCommand<T> {
|
|||||||
private Function<T, ?> senderFunction;
|
private Function<T, ?> senderFunction;
|
||||||
AbstractValidator<T, T> validator;
|
AbstractValidator<T, T> validator;
|
||||||
boolean noTabComplete;
|
boolean noTabComplete;
|
||||||
int comparableValue;
|
|
||||||
|
private Parameter[] parameters;
|
||||||
|
|
||||||
private CommandPart<T> commandPart;
|
private CommandPart<T> commandPart;
|
||||||
|
|
||||||
SubCommand(AbstractSWCommand<T> abstractSWCommand, Method method, String[] subCommand, Map<String, AbstractTypeMapper<T, ?>> localTypeMapper, Map<String, AbstractValidator<T, ?>> localValidator, boolean help, String[] description, boolean noTabComplete) {
|
boolean isHelp = false;
|
||||||
|
|
||||||
|
SubCommand(AbstractSWCommand<T> abstractSWCommand, Method method, String[] subCommand, Map<String, AbstractTypeMapper<T, ?>> localTypeMapper, Map<String, AbstractValidator<T, ?>> localValidator, String[] description, boolean noTabComplete) {
|
||||||
this.abstractSWCommand = abstractSWCommand;
|
this.abstractSWCommand = abstractSWCommand;
|
||||||
this.method = method;
|
this.method = method;
|
||||||
try {
|
try {
|
||||||
@ -55,17 +61,39 @@ public class SubCommand<T> {
|
|||||||
this.description = description;
|
this.description = description;
|
||||||
this.noTabComplete = noTabComplete;
|
this.noTabComplete = noTabComplete;
|
||||||
|
|
||||||
Parameter[] parameters = method.getParameters();
|
parameters = method.getParameters();
|
||||||
comparableValue = parameters[parameters.length - 1].isVarArgs() ? Integer.MAX_VALUE : -parameters.length;
|
AbstractSWCommand.Validator validator = parameters[0].getAnnotation(AbstractSWCommand.Validator.class);
|
||||||
|
if (validator != null) {
|
||||||
|
this.validator = (AbstractValidator<T, T>) SWCommandUtils.getValidator(validator, parameters[0].getType(), localValidator);
|
||||||
|
if (validator.invert()) {
|
||||||
|
AbstractValidator<T, T> current = this.validator;
|
||||||
|
this.validator = (sender, value, messageSender) -> !current.validate(sender, value, messageSender);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
validator = (AbstractValidator<T, T>) SWCommandUtils.getValidator(parameters[0], localValidator);
|
commandPart = generateCommandPart(abstractSWCommand, subCommand, parameters, localTypeMapper, localValidator);
|
||||||
|
if (commandPart != null) isHelp = commandPart.isHelp();
|
||||||
commandPart = SWCommandUtils.generateCommandPart(abstractSWCommand, help, subCommand, parameters, localTypeMapper, localValidator);
|
|
||||||
|
|
||||||
senderPredicate = t -> parameters[0].getType().isAssignableFrom(t.getClass());
|
senderPredicate = t -> parameters[0].getType().isAssignableFrom(t.getClass());
|
||||||
senderFunction = t -> parameters[0].getType().cast(t);
|
senderFunction = t -> parameters[0].getType().cast(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(SubCommand<T> o) {
|
||||||
|
int tLength = parameters.length + subCommand.length;
|
||||||
|
int oLength = o.parameters.length + o.subCommand.length;
|
||||||
|
|
||||||
|
boolean tVarArgs = parameters[parameters.length - 1].isVarArgs();
|
||||||
|
boolean oVarArgs = o.parameters[o.parameters.length - 1].isVarArgs();
|
||||||
|
|
||||||
|
if (tVarArgs) tLength *= -1;
|
||||||
|
if (oVarArgs) oLength *= -1;
|
||||||
|
|
||||||
|
if (tVarArgs && oVarArgs) return Integer.compare(tLength, oLength);
|
||||||
|
|
||||||
|
return -Integer.compare(tLength, oLength);
|
||||||
|
}
|
||||||
|
|
||||||
boolean invoke(Consumer<Runnable> errors, T sender, String alias, String[] args) {
|
boolean invoke(Consumer<Runnable> errors, T sender, String alias, String[] args) {
|
||||||
try {
|
try {
|
||||||
if (!senderPredicate.test(sender)) {
|
if (!senderPredicate.test(sender)) {
|
||||||
@ -97,7 +125,7 @@ public class SubCommand<T> {
|
|||||||
objects.add(0, senderFunction.apply(sender));
|
objects.add(0, senderFunction.apply(sender));
|
||||||
method.invoke(abstractSWCommand, objects.toArray());
|
method.invoke(abstractSWCommand, objects.toArray());
|
||||||
}
|
}
|
||||||
} catch (CommandNoHelpException | CommandFrameworkException e) {
|
} catch (CommandFrameworkException e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (CommandParseException e) {
|
} catch (CommandParseException e) {
|
||||||
return false;
|
return false;
|
||||||
@ -110,18 +138,155 @@ public class SubCommand<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<String> tabComplete(T sender, String[] args) {
|
List<String> tabComplete(T sender, String[] args) {
|
||||||
if (validator != null) {
|
if (validator != null && !validator.validate(sender, sender, (s, objects) -> {})) {
|
||||||
if (!validator.validate(sender, sender, (s, objects) -> {
|
return null;
|
||||||
// ignore
|
|
||||||
})) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (commandPart == null) {
|
if (commandPart == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
List<String> list = new ArrayList<>();
|
List<String> list = new ArrayList<>();
|
||||||
commandPart.generateTabComplete(list, sender, args, 0);
|
commandPart.generateTabComplete(list, sender, args, new ArrayList<>(), 0);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static <T> CommandPart<T> generateCommandPart(AbstractSWCommand<T> command, String[] subCommand, Parameter[] parameters, Map<String, AbstractTypeMapper<T, ?>> localTypeMapper, Map<String, AbstractValidator<T, ?>> localValidator) {
|
||||||
|
CommandPart<T> first = null;
|
||||||
|
CommandPart<T> current = null;
|
||||||
|
for (String s : subCommand) {
|
||||||
|
CommandPart commandPart = new CommandPart(command, SWCommandUtils.createMapper(s), null, null, null, -1);
|
||||||
|
commandPart.addValidator(NULL_FILTER);
|
||||||
|
commandPart.setIgnoreAsArgument(true);
|
||||||
|
if (current != null) {
|
||||||
|
current.setNext(commandPart);
|
||||||
|
}
|
||||||
|
current = commandPart;
|
||||||
|
if (first == null) {
|
||||||
|
first = current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 1; i < parameters.length; i++) {
|
||||||
|
Parameter parameter = parameters[i];
|
||||||
|
AbstractTypeMapper<T, ?> typeMapper = handleImplicitTypeMapper(parameter, localTypeMapper);
|
||||||
|
Class<?> varArgType = parameter.isVarArgs() ? parameter.getType().getComponentType() : null;
|
||||||
|
AbstractSWCommand.OptionalValue optionalValue = parameter.getAnnotation(AbstractSWCommand.OptionalValue.class);
|
||||||
|
|
||||||
|
CommandPart<T> commandPart = new CommandPart<>(command, typeMapper, varArgType, optionalValue != null ? optionalValue.value() : null, parameter, i);
|
||||||
|
commandPart.setOnlyUseIfNoneIsGiven(optionalValue != null && optionalValue.onlyUINIG());
|
||||||
|
handleImplicitTypeValidator(parameter, commandPart, localValidator);
|
||||||
|
if (parameter.getAnnotation(AbstractSWCommand.AllowNull.class) == null) {
|
||||||
|
commandPart.addValidator((AbstractValidator<T, Object>) NULL_FILTER);
|
||||||
|
}
|
||||||
|
if (current != null) {
|
||||||
|
current.setNext(commandPart);
|
||||||
|
}
|
||||||
|
current = commandPart;
|
||||||
|
if (first == null) {
|
||||||
|
first = current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> AbstractTypeMapper<T, Object> handleImplicitTypeMapper(Parameter parameter, Map<String, AbstractTypeMapper<T, ?>> localTypeMapper) {
|
||||||
|
Class<?> type = parameter.getType();
|
||||||
|
if (parameter.isVarArgs()) {
|
||||||
|
type = type.getComponentType();
|
||||||
|
}
|
||||||
|
|
||||||
|
Annotation[] annotations = parameter.getAnnotations();
|
||||||
|
Constructor<?> sourceConstructor = null;
|
||||||
|
Annotation sourceAnnotation = null;
|
||||||
|
List<Constructor<?>> parentConstructors = new ArrayList<>();
|
||||||
|
List<Annotation> parentAnnotations = new ArrayList<>();
|
||||||
|
for (Annotation annotation : annotations) {
|
||||||
|
CommandMetaData.ImplicitTypeMapper implicitTypeMapper = annotation.annotationType().getAnnotation(CommandMetaData.ImplicitTypeMapper.class);
|
||||||
|
if (implicitTypeMapper == null) continue;
|
||||||
|
Class<?> clazz = implicitTypeMapper.handler();
|
||||||
|
if (!AbstractTypeMapper.class.isAssignableFrom(clazz)) continue;
|
||||||
|
Constructor<?>[] constructors = clazz.getConstructors();
|
||||||
|
if (constructors.length != 1) continue;
|
||||||
|
Constructor<?> constructor = constructors[0];
|
||||||
|
if (needsTypeMapper(constructor)) {
|
||||||
|
parentConstructors.add(constructor);
|
||||||
|
parentAnnotations.add(annotation);
|
||||||
|
} else {
|
||||||
|
if (sourceAnnotation != null) {
|
||||||
|
throw new IllegalArgumentException("Multiple source type mappers found for parameter " + parameter);
|
||||||
|
}
|
||||||
|
sourceConstructor = constructor;
|
||||||
|
sourceAnnotation = annotation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractTypeMapper<T, Object> current;
|
||||||
|
if (sourceAnnotation != null) {
|
||||||
|
current = createInstance(sourceConstructor, sourceAnnotation, type, localTypeMapper);
|
||||||
|
} else {
|
||||||
|
current = (AbstractTypeMapper<T, Object>) SWCommandUtils.getTypeMapper(parameter, localTypeMapper);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < parentConstructors.size(); i++) {
|
||||||
|
Constructor<?> constructor = parentConstructors.get(i);
|
||||||
|
Annotation annotation = parentAnnotations.get(i);
|
||||||
|
current = createInstance(constructor, annotation, type, localTypeMapper, current);
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean needsTypeMapper(Constructor<?> constructor) {
|
||||||
|
Class<?>[] parameterTypes = constructor.getParameterTypes();
|
||||||
|
for (Class<?> parameterType : parameterTypes) {
|
||||||
|
if (AbstractTypeMapper.class.isAssignableFrom(parameterType)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> void handleImplicitTypeValidator(Parameter parameter, CommandPart<T> commandPart, Map<String, AbstractValidator<T, ?>> localValidator) {
|
||||||
|
Annotation[] annotations = parameter.getAnnotations();
|
||||||
|
Map<Integer, List<AbstractValidator<T, Object>>> validators = new HashMap<>();
|
||||||
|
for (Annotation annotation : annotations) {
|
||||||
|
CommandMetaData.ImplicitValidator implicitValidator = annotation.annotationType().getAnnotation(CommandMetaData.ImplicitValidator.class);
|
||||||
|
if (implicitValidator == null) continue;
|
||||||
|
Class<?> clazz = implicitValidator.handler();
|
||||||
|
if (!AbstractValidator.class.isAssignableFrom(clazz)) continue;
|
||||||
|
Constructor<?>[] constructors = clazz.getConstructors();
|
||||||
|
if (constructors.length != 1) continue;
|
||||||
|
AbstractValidator<T, Object> validator = createInstance(constructors[0], annotation, commandPart.getType(), localValidator);
|
||||||
|
validators.computeIfAbsent(implicitValidator.order(), integer -> new ArrayList<>()).add(validator);
|
||||||
|
}
|
||||||
|
List<Integer> keys = new ArrayList<>(validators.keySet());
|
||||||
|
keys.sort(Integer::compareTo);
|
||||||
|
for (Integer key : keys) {
|
||||||
|
List<AbstractValidator<T, Object>> list = validators.get(key);
|
||||||
|
for (AbstractValidator<T, Object> validator : list) {
|
||||||
|
commandPart.addValidator(validator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> T createInstance(Constructor<?> constructor, Object... parameter) {
|
||||||
|
Class<?>[] types = constructor.getParameterTypes();
|
||||||
|
List<Object> objects = new ArrayList<>();
|
||||||
|
for (Class<?> clazz : types) {
|
||||||
|
boolean found = false;
|
||||||
|
for (Object o : parameter) {
|
||||||
|
if (clazz.isAssignableFrom(o.getClass())) {
|
||||||
|
objects.add(o);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
throw new RuntimeException("Could not find type " + clazz + " for constructor " + constructor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return (T) constructor.newInstance(objects.toArray());
|
||||||
|
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final AbstractValidator<?, Object> NULL_FILTER = (sender, value, messageSender) -> value != null;
|
||||||
}
|
}
|
||||||
|
@ -51,25 +51,29 @@ public class TabCompletionCache {
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
private static class Key {
|
private static class Key {
|
||||||
private Object sender;
|
private Object sender;
|
||||||
|
private String arg;
|
||||||
private AbstractTypeMapper<?, ?> typeMapper;
|
private AbstractTypeMapper<?, ?> typeMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
private static class TabCompletions {
|
private static class TabCompletions {
|
||||||
private AbstractSWCommand<?> command;
|
|
||||||
private long timestamp;
|
private long timestamp;
|
||||||
private Collection<String> tabCompletions;
|
private Collection<String> tabCompletions;
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection<String> tabComplete(Object sender, AbstractTypeMapper<?, ?> typeMapper, AbstractSWCommand<?> command, Supplier<Collection<String>> tabCompleteSupplier) {
|
Collection<String> tabComplete(Object sender, String arg, AbstractTypeMapper<Object, ?> typeMapper, Supplier<Collection<String>> tabCompleteSupplier) {
|
||||||
if (!cached.contains(typeMapper)) return tabCompleteSupplier.get();
|
if (!cached.contains(typeMapper)) return tabCompleteSupplier.get();
|
||||||
Key key = global.contains(typeMapper) ? new Key(null, typeMapper) : new Key(sender, typeMapper);
|
|
||||||
|
String normalizedArg = typeMapper.normalize(sender, arg);
|
||||||
|
if (normalizedArg == null) normalizedArg = "";
|
||||||
|
Key key = new Key(global.contains(typeMapper) ? null : sender, normalizedArg, typeMapper);
|
||||||
|
|
||||||
TabCompletions tabCompletions = tabCompletionCache.computeIfAbsent(key, ignore -> {
|
TabCompletions tabCompletions = tabCompletionCache.computeIfAbsent(key, ignore -> {
|
||||||
return new TabCompletions(command, System.currentTimeMillis(), tabCompleteSupplier.get());
|
return new TabCompletions(System.currentTimeMillis(), tabCompleteSupplier.get());
|
||||||
});
|
});
|
||||||
if (tabCompletions.command != command || System.currentTimeMillis() - tabCompletions.timestamp > cacheDuration.get(typeMapper)) {
|
|
||||||
tabCompletions = new TabCompletions(command, System.currentTimeMillis(), tabCompleteSupplier.get());
|
if (System.currentTimeMillis() - tabCompletions.timestamp > cacheDuration.get(typeMapper)) {
|
||||||
tabCompletionCache.put(key, tabCompletions);
|
tabCompletions.tabCompletions = tabCompleteSupplier.get();
|
||||||
}
|
}
|
||||||
tabCompletions.timestamp = System.currentTimeMillis();
|
tabCompletions.timestamp = System.currentTimeMillis();
|
||||||
return tabCompletions.tabCompletions;
|
return tabCompletions.tabCompletions;
|
||||||
|
@ -23,12 +23,16 @@ import de.steamwar.linkage.plan.BuildPlan;
|
|||||||
import de.steamwar.linkage.plan.FieldBuilder;
|
import de.steamwar.linkage.plan.FieldBuilder;
|
||||||
import de.steamwar.linkage.plan.MethodBuilder;
|
import de.steamwar.linkage.plan.MethodBuilder;
|
||||||
import de.steamwar.linkage.types.Plain_GENERIC;
|
import de.steamwar.linkage.types.Plain_GENERIC;
|
||||||
|
import lombok.Cleanup;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
import javax.annotation.processing.*;
|
import javax.annotation.processing.*;
|
||||||
import javax.lang.model.SourceVersion;
|
import javax.lang.model.SourceVersion;
|
||||||
import javax.lang.model.element.*;
|
import javax.lang.model.element.ElementKind;
|
||||||
|
import javax.lang.model.element.Modifier;
|
||||||
|
import javax.lang.model.element.TypeElement;
|
||||||
|
import javax.lang.model.element.VariableElement;
|
||||||
import javax.lang.model.type.DeclaredType;
|
import javax.lang.model.type.DeclaredType;
|
||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
import javax.tools.Diagnostic;
|
import javax.tools.Diagnostic;
|
||||||
@ -39,6 +43,7 @@ import java.nio.file.Path;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@SupportedAnnotationTypes("de.steamwar.linkage.Linked")
|
@SupportedAnnotationTypes("de.steamwar.linkage.Linked")
|
||||||
public class LinkageProcessor extends AbstractProcessor {
|
public class LinkageProcessor extends AbstractProcessor {
|
||||||
@ -49,7 +54,6 @@ public class LinkageProcessor extends AbstractProcessor {
|
|||||||
private static String pluginMain;
|
private static String pluginMain;
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
private String packageName;
|
|
||||||
private String className;
|
private String className;
|
||||||
|
|
||||||
private Messager messager;
|
private Messager messager;
|
||||||
@ -69,7 +73,6 @@ public class LinkageProcessor extends AbstractProcessor {
|
|||||||
|
|
||||||
messager = processingEnv.getMessager();
|
messager = processingEnv.getMessager();
|
||||||
|
|
||||||
packageName = "de.steamwar." + name + ".linkage";
|
|
||||||
className = "LinkageUtils";
|
className = "LinkageUtils";
|
||||||
mainClass();
|
mainClass();
|
||||||
}
|
}
|
||||||
@ -87,22 +90,15 @@ public class LinkageProcessor extends AbstractProcessor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
context = pluginYMLFile.get().getName().equals("bungee.yml") ? Context.BUNGEE : Context.SPIGOT;
|
context = pluginYMLFile.get().getName().equals("bungee.yml") ? Context.BUNGEE : Context.SPIGOT;
|
||||||
Optional<String> mainName = getMainName(pluginYMLFile.get());
|
@Cleanup BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(pluginYMLFile.get())));
|
||||||
if (!mainName.isPresent()) {
|
Optional<String> mainName = reader.lines()
|
||||||
|
.filter(line -> line.startsWith("main:"))
|
||||||
|
.map(line -> line.substring(line.indexOf(':') + 1).trim())
|
||||||
|
.findFirst();
|
||||||
|
if (mainName.isPresent()) {
|
||||||
|
pluginMain = mainName.get();
|
||||||
|
} else {
|
||||||
messager.printMessage(Diagnostic.Kind.ERROR, "Could not find main class in plugin.yml or bungee.yml");
|
messager.printMessage(Diagnostic.Kind.ERROR, "Could not find main class in plugin.yml or bungee.yml");
|
||||||
return;
|
|
||||||
}
|
|
||||||
pluginMain = mainName.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
private Optional<String> getMainName(File pluginYML) {
|
|
||||||
if (!pluginYML.exists()) return Optional.empty();
|
|
||||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(pluginYML)))) {
|
|
||||||
return reader.lines()
|
|
||||||
.filter(line -> line.startsWith("main:"))
|
|
||||||
.map(line -> line.substring(line.indexOf(':') + 1).trim())
|
|
||||||
.findFirst();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,31 +109,30 @@ public class LinkageProcessor extends AbstractProcessor {
|
|||||||
processed = true;
|
processed = true;
|
||||||
|
|
||||||
Writer writer = processingEnv.getFiler().createSourceFile("de.steamwar." + name + ".linkage.LinkageUtils").openWriter();
|
Writer writer = processingEnv.getFiler().createSourceFile("de.steamwar." + name + ".linkage.LinkageUtils").openWriter();
|
||||||
|
BuildPlan buildPlan = new BuildPlan("de.steamwar." + name + ".linkage", className);
|
||||||
|
|
||||||
BuildPlan buildPlan = new BuildPlan(packageName, className);
|
Set<TypeElement> elements = roundEnv.getElementsAnnotatedWith(Linked.class).stream()
|
||||||
|
.filter(element -> element.getKind() == ElementKind.CLASS)
|
||||||
|
.map(TypeElement.class::cast)
|
||||||
|
.peek(typeElement -> System.out.println("Found element: " + typeElement.getQualifiedName().toString()))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
Map<Set<String>, List<TypeElement>> groupedByChecks = elements.stream()
|
||||||
|
.collect(Collectors.groupingBy(element -> checks(element, buildPlan)));
|
||||||
|
|
||||||
Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(Linked.class);
|
|
||||||
Map<String, TypeElement> neededFields = new HashMap<>();
|
Map<String, TypeElement> neededFields = new HashMap<>();
|
||||||
Set<Runnable> fieldInjections = new HashSet<>();
|
Set<Runnable> fieldInjections = new HashSet<>();
|
||||||
for (Element element : elements) {
|
for (TypeElement typeElement : elements) {
|
||||||
if (element.getKind() != ElementKind.CLASS) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
TypeElement typeElement = (TypeElement) element;
|
|
||||||
Linked linked = element.getAnnotation(Linked.class);
|
|
||||||
if (linked == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (getLinkagesOfType(typeElement).size() > 1) {
|
if (getLinkagesOfType(typeElement).size() > 1) {
|
||||||
neededFields.put(typeElement.getQualifiedName().toString(), typeElement);
|
neededFields.put(typeElement.getQualifiedName().toString(), typeElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<VariableElement> variableElements = typeElement.getEnclosedElements().stream().filter(e -> e.getKind() == ElementKind.FIELD).map(VariableElement.class::cast).filter(e -> {
|
List<VariableElement> variableElements = typeElement.getEnclosedElements().stream()
|
||||||
return e.getAnnotation(LinkedInstance.class) != null;
|
.filter(e -> e.getKind() == ElementKind.FIELD)
|
||||||
}).collect(Collectors.toList());
|
.map(VariableElement.class::cast)
|
||||||
if (variableElements.isEmpty()) {
|
.filter(e -> e.getAnnotation(LinkedInstance.class) != null)
|
||||||
continue;
|
.collect(Collectors.toList());
|
||||||
}
|
if (variableElements.isEmpty()) continue;
|
||||||
|
|
||||||
for (VariableElement variableElement : variableElements) {
|
for (VariableElement variableElement : variableElements) {
|
||||||
if (!variableElement.getModifiers().contains(Modifier.PUBLIC)) {
|
if (!variableElement.getModifiers().contains(Modifier.PUBLIC)) {
|
||||||
@ -177,30 +172,37 @@ public class LinkageProcessor extends AbstractProcessor {
|
|||||||
fieldInjections.forEach(Runnable::run);
|
fieldInjections.forEach(Runnable::run);
|
||||||
|
|
||||||
Map<String, MethodBuilder> methods = new HashMap<>();
|
Map<String, MethodBuilder> methods = new HashMap<>();
|
||||||
for (Element element : elements) {
|
for (Map.Entry<Set<String>, List<TypeElement>> entry : groupedByChecks.entrySet()) {
|
||||||
if (element.getKind() != ElementKind.CLASS) {
|
Map<String, Map<TypeElement, List<LinkageType>>> groupedByMethod = new HashMap<>();
|
||||||
continue;
|
for (TypeElement typeElement : entry.getValue()) {
|
||||||
}
|
for (Map.Entry<String, List<LinkageType>> linkages : getLinkagesOfType(typeElement).entrySet()) {
|
||||||
TypeElement typeElement = (TypeElement) element;
|
groupedByMethod.computeIfAbsent(linkages.getKey(), ignored -> new HashMap<>())
|
||||||
|
.put(typeElement, linkages.getValue());
|
||||||
System.out.println("Found element: " + typeElement.getQualifiedName().toString());
|
}
|
||||||
Map<String, List<LinkageType>> linkages = getLinkagesOfType(typeElement);
|
|
||||||
if (linkages.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<String, List<LinkageType>> entry : linkages.entrySet()) {
|
for (Map.Entry<String, Map<TypeElement, List<LinkageType>>> group : groupedByMethod.entrySet()) {
|
||||||
MethodBuilder method = methods.computeIfAbsent(entry.getKey(), s -> {
|
MethodBuilder method = methods.computeIfAbsent(group.getKey(), s -> {
|
||||||
MethodBuilder methodBuilder = new MethodBuilder(s, "void");
|
MethodBuilder methodBuilder = new MethodBuilder(s, "void");
|
||||||
buildPlan.addMethod(methodBuilder);
|
buildPlan.addMethod(methodBuilder);
|
||||||
return methodBuilder;
|
return methodBuilder;
|
||||||
});
|
});
|
||||||
for (LinkageType type : entry.getValue()) {
|
|
||||||
specialElements(typeElement, buildPlan, method::addLine, () -> {
|
if (!entry.getKey().isEmpty()) method.addLine("if (" + String.join(" && ", entry.getKey()) + ") {");
|
||||||
|
for (Map.Entry<TypeElement, List<LinkageType>> toGenerate : group.getValue().entrySet()) {
|
||||||
|
TypeElement typeElement = toGenerate.getKey();
|
||||||
|
String instance = getElement(typeElement, neededFields);
|
||||||
|
if (toGenerate.getValue().size() > 1 && instance.startsWith("new ")) {
|
||||||
|
method.addLine(typeElement.getSimpleName() + " local" + typeElement.getSimpleName().toString() + " = " + instance + ";");
|
||||||
|
instance = "local" + typeElement.getSimpleName().toString();
|
||||||
|
}
|
||||||
|
String finalInstance = instance;
|
||||||
|
toGenerate.getValue().forEach(linkageType -> {
|
||||||
buildPlan.addImport(typeElement.getQualifiedName().toString());
|
buildPlan.addImport(typeElement.getQualifiedName().toString());
|
||||||
type.generateCode(buildPlan, method, getElement(typeElement, neededFields), typeElement);
|
linkageType.generateCode(buildPlan, method, finalInstance, typeElement);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (!entry.getKey().isEmpty()) method.addLine("}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,21 +213,21 @@ public class LinkageProcessor extends AbstractProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String getElement(TypeElement typeElement, Map<String, TypeElement> neededFields) {
|
private String getElement(TypeElement typeElement, Map<String, TypeElement> neededFields) {
|
||||||
|
String s = typeElement.getSimpleName().toString();
|
||||||
if (neededFields.containsKey(typeElement.getQualifiedName().toString())) {
|
if (neededFields.containsKey(typeElement.getQualifiedName().toString())) {
|
||||||
String s = typeElement.getSimpleName().toString();
|
|
||||||
return s.substring(0, 1).toLowerCase() + s.substring(1);
|
return s.substring(0, 1).toLowerCase() + s.substring(1);
|
||||||
}
|
}
|
||||||
return "new " + typeElement.getSimpleName().toString() + "()";
|
return "new " + s + "()";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void specialElements(TypeElement typeElement, BuildPlan buildPlan, Consumer<String> stringConsumer, Runnable inner) {
|
private Set<String> checks(TypeElement typeElement, BuildPlan buildPlan) {
|
||||||
|
Set<String> checks = new HashSet<>();
|
||||||
MinVersion minVersion = typeElement.getAnnotation(MinVersion.class);
|
MinVersion minVersion = typeElement.getAnnotation(MinVersion.class);
|
||||||
MaxVersion maxVersion = typeElement.getAnnotation(MaxVersion.class);
|
MaxVersion maxVersion = typeElement.getAnnotation(MaxVersion.class);
|
||||||
EventMode eventMode = typeElement.getAnnotation(EventMode.class);
|
EventMode eventMode = typeElement.getAnnotation(EventMode.class);
|
||||||
PluginCheck[] pluginChecks = typeElement.getAnnotationsByType(PluginCheck.class);
|
PluginCheck[] pluginChecks = typeElement.getAnnotationsByType(PluginCheck.class);
|
||||||
if (context == Context.SPIGOT) {
|
if (context == Context.SPIGOT) {
|
||||||
errorOnNonNull(typeElement, eventMode);
|
errorOnNonNull(typeElement, eventMode);
|
||||||
List<String> checks = new ArrayList<>();
|
|
||||||
if (minVersion != null) {
|
if (minVersion != null) {
|
||||||
buildPlan.addImport("de.steamwar.core.Core");
|
buildPlan.addImport("de.steamwar.core.Core");
|
||||||
checks.add("Core.getVersion() >= " + minVersion.value());
|
checks.add("Core.getVersion() >= " + minVersion.value());
|
||||||
@ -240,12 +242,8 @@ public class LinkageProcessor extends AbstractProcessor {
|
|||||||
return "Bukkit.getPluginManager().getPlugin(\"" + pluginCheck.value() + "\") " + (pluginCheck.has() == PluginCheck.Has.THIS ? "!" : "=") + "= null";
|
return "Bukkit.getPluginManager().getPlugin(\"" + pluginCheck.value() + "\") " + (pluginCheck.has() == PluginCheck.Has.THIS ? "!" : "=") + "= null";
|
||||||
}).forEach(checks::add);
|
}).forEach(checks::add);
|
||||||
}
|
}
|
||||||
if (!checks.isEmpty()) stringConsumer.accept("if (" + String.join(" && ", checks) + ") {");
|
|
||||||
inner.run();
|
|
||||||
if (!checks.isEmpty()) stringConsumer.accept("}");
|
|
||||||
} else {
|
} else {
|
||||||
errorOnNonNull(typeElement, minVersion, maxVersion);
|
errorOnNonNull(typeElement, minVersion, maxVersion);
|
||||||
List<String> checks = new ArrayList<>();
|
|
||||||
if (eventMode != null) {
|
if (eventMode != null) {
|
||||||
buildPlan.addImport("de.steamwar.bungeecore.BungeeCore");
|
buildPlan.addImport("de.steamwar.bungeecore.BungeeCore");
|
||||||
checks.add(eventMode.value().getPrefix() + "BungeeCore.EVENT_MODE");
|
checks.add(eventMode.value().getPrefix() + "BungeeCore.EVENT_MODE");
|
||||||
@ -256,10 +254,15 @@ public class LinkageProcessor extends AbstractProcessor {
|
|||||||
return "BungeeCord.getPluginManager().getPlugin(\"" + pluginCheck.value() + "\") " + (pluginCheck.has() == PluginCheck.Has.THIS ? "!" : "=") + "= null";
|
return "BungeeCord.getPluginManager().getPlugin(\"" + pluginCheck.value() + "\") " + (pluginCheck.has() == PluginCheck.Has.THIS ? "!" : "=") + "= null";
|
||||||
}).forEach(checks::add);
|
}).forEach(checks::add);
|
||||||
}
|
}
|
||||||
if (!checks.isEmpty()) stringConsumer.accept("if (" + String.join(" && ", checks) + ") {");
|
|
||||||
inner.run();
|
|
||||||
if (!checks.isEmpty()) stringConsumer.accept("}");
|
|
||||||
}
|
}
|
||||||
|
return checks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void specialElements(TypeElement typeElement, BuildPlan buildPlan, Consumer<String> stringConsumer, Runnable inner) {
|
||||||
|
Set<String> checks = checks(typeElement, buildPlan);
|
||||||
|
if (!checks.isEmpty()) stringConsumer.accept("if (" + String.join(" && ", checks) + ") {");
|
||||||
|
inner.run();
|
||||||
|
if (!checks.isEmpty()) stringConsumer.accept("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void errorOnNonNull(TypeElement typeElement, Annotation... annotations) {
|
private void errorOnNonNull(TypeElement typeElement, Annotation... annotations) {
|
||||||
@ -274,16 +277,10 @@ public class LinkageProcessor extends AbstractProcessor {
|
|||||||
|
|
||||||
private Map<String, List<LinkageType>> getLinkagesOfType(TypeElement typeElement) {
|
private Map<String, List<LinkageType>> getLinkagesOfType(TypeElement typeElement) {
|
||||||
Map<String, List<LinkageType>> linkages = new HashMap<>();
|
Map<String, List<LinkageType>> linkages = new HashMap<>();
|
||||||
LinkageType superClassType = resolveSingle(typeElement.getSuperclass());
|
Stream.concat(Stream.of(typeElement.getSuperclass()), typeElement.getInterfaces().stream())
|
||||||
if (superClassType != null) {
|
.map(this::resolveSingle)
|
||||||
linkages.computeIfAbsent(superClassType.method(), s -> new ArrayList<>()).add(superClassType);
|
.filter(Objects::nonNull)
|
||||||
}
|
.forEach(linkageType -> linkages.computeIfAbsent(linkageType.method(), s -> new ArrayList<>()).add(linkageType));
|
||||||
for (TypeMirror typeMirror : typeElement.getInterfaces()) {
|
|
||||||
LinkageType interfaceType = resolveSingle(typeMirror);
|
|
||||||
if (interfaceType != null) {
|
|
||||||
linkages.computeIfAbsent(interfaceType.method(), s -> new ArrayList<>()).add(interfaceType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (linkages.size() == 1 && linkages.containsKey("unlink")) {
|
if (linkages.size() == 1 && linkages.containsKey("unlink")) {
|
||||||
linkages.put(plain_GENERIC.method(), Collections.singletonList(plain_GENERIC));
|
linkages.put(plain_GENERIC.method(), Collections.singletonList(plain_GENERIC));
|
||||||
}
|
}
|
||||||
|
67
src/de/steamwar/sql/BannedUserIPs.java
Normale Datei
67
src/de/steamwar/sql/BannedUserIPs.java
Normale Datei
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.sql;
|
||||||
|
|
||||||
|
import de.steamwar.sql.internal.Field;
|
||||||
|
import de.steamwar.sql.internal.SelectStatement;
|
||||||
|
import de.steamwar.sql.internal.Statement;
|
||||||
|
import de.steamwar.sql.internal.Table;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class BannedUserIPs {
|
||||||
|
|
||||||
|
private static final Table<BannedUserIPs> table = new Table<>(BannedUserIPs.class);
|
||||||
|
|
||||||
|
private static final SelectStatement<BannedUserIPs> getByID = table.selectFields("UserID");
|
||||||
|
private static final SelectStatement<BannedUserIPs> getByIP = new SelectStatement<>(table, "SELECT * FROM BannedUserIPs WHERE IP = ? ORDER BY Timestamp DESC");
|
||||||
|
private static final Statement banIP = table.insertAll();
|
||||||
|
private static final Statement unbanIPs = table.deleteFields("UserID");
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Field(keys = {Table.PRIMARY})
|
||||||
|
private final int userID;
|
||||||
|
@Getter
|
||||||
|
@Field(def = "CURRENT_TIMESTAMP")
|
||||||
|
private final Timestamp timestamp;
|
||||||
|
@Field(keys = {Table.PRIMARY})
|
||||||
|
private final String ip;
|
||||||
|
|
||||||
|
public static List<BannedUserIPs> get(int userID) {
|
||||||
|
return getByID.listSelect(userID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<BannedUserIPs> get(String ip) {
|
||||||
|
return getByIP.listSelect(ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void banIP(int userID, String ip){
|
||||||
|
banIP.update(userID, Timestamp.from(Instant.now()), ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void unbanIPs(int userID) {
|
||||||
|
unbanIPs.update(userID);
|
||||||
|
}
|
||||||
|
}
|
@ -21,6 +21,7 @@ package de.steamwar.sql;
|
|||||||
|
|
||||||
import de.steamwar.sql.internal.Field;
|
import de.steamwar.sql.internal.Field;
|
||||||
import de.steamwar.sql.internal.SelectStatement;
|
import de.steamwar.sql.internal.SelectStatement;
|
||||||
|
import de.steamwar.sql.internal.Statement;
|
||||||
import de.steamwar.sql.internal.Table;
|
import de.steamwar.sql.internal.Table;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@ -36,6 +37,12 @@ public class BauweltMember {
|
|||||||
private static final Table<BauweltMember> table = new Table<>(BauweltMember.class);
|
private static final Table<BauweltMember> table = new Table<>(BauweltMember.class);
|
||||||
private static final SelectStatement<BauweltMember> getMember = table.select(Table.PRIMARY);
|
private static final SelectStatement<BauweltMember> getMember = table.select(Table.PRIMARY);
|
||||||
private static final SelectStatement<BauweltMember> getMembers = table.selectFields("BauweltID");
|
private static final SelectStatement<BauweltMember> getMembers = table.selectFields("BauweltID");
|
||||||
|
private static final Statement update = table.insertAll();
|
||||||
|
private static final Statement delete = table.delete(Table.PRIMARY);
|
||||||
|
|
||||||
|
public static void addMember(UUID ownerID, UUID memberID) {
|
||||||
|
new BauweltMember(SteamwarUser.get(ownerID).getId(), SteamwarUser.get(memberID).getId(), false, false).updateDB();
|
||||||
|
}
|
||||||
|
|
||||||
public static BauweltMember getBauMember(UUID ownerID, UUID memberID){
|
public static BauweltMember getBauMember(UUID ownerID, UUID memberID){
|
||||||
return getBauMember(SteamwarUser.get(ownerID).getId(), SteamwarUser.get(memberID).getId());
|
return getBauMember(SteamwarUser.get(ownerID).getId(), SteamwarUser.get(memberID).getId());
|
||||||
@ -43,7 +50,7 @@ public class BauweltMember {
|
|||||||
|
|
||||||
public static BauweltMember getBauMember(int ownerID, int memberID){
|
public static BauweltMember getBauMember(int ownerID, int memberID){
|
||||||
BauweltMember member = memberCache.get(memberID);
|
BauweltMember member = memberCache.get(memberID);
|
||||||
if(member != null)
|
if(member != null && member.bauweltID == ownerID)
|
||||||
return member;
|
return member;
|
||||||
return getMember.select(ownerID, memberID);
|
return getMember.select(ownerID, memberID);
|
||||||
}
|
}
|
||||||
@ -63,11 +70,11 @@ public class BauweltMember {
|
|||||||
@Field(keys = {Table.PRIMARY})
|
@Field(keys = {Table.PRIMARY})
|
||||||
private final int memberID;
|
private final int memberID;
|
||||||
@Getter
|
@Getter
|
||||||
@Field
|
@Field(def = "0")
|
||||||
private final boolean worldEdit;
|
private boolean worldEdit;
|
||||||
@Getter
|
@Getter
|
||||||
@Field
|
@Field(def = "0")
|
||||||
private final boolean world;
|
private boolean world;
|
||||||
|
|
||||||
public BauweltMember(int bauweltID, int memberID, boolean worldEdit, boolean world) {
|
public BauweltMember(int bauweltID, int memberID, boolean worldEdit, boolean world) {
|
||||||
this.bauweltID = bauweltID;
|
this.bauweltID = bauweltID;
|
||||||
@ -76,4 +83,23 @@ public class BauweltMember {
|
|||||||
this.world = world;
|
this.world = world;
|
||||||
memberCache.put(memberID, this);
|
memberCache.put(memberID, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setWorldEdit(boolean worldEdit) {
|
||||||
|
this.worldEdit = worldEdit;
|
||||||
|
updateDB();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWorld(boolean world) {
|
||||||
|
this.world = world;
|
||||||
|
updateDB();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDB(){
|
||||||
|
update.update(bauweltID, memberID, worldEdit, world);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(){
|
||||||
|
delete.update(bauweltID, memberID);
|
||||||
|
memberCache.remove(memberID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ package de.steamwar.sql;
|
|||||||
|
|
||||||
import de.steamwar.sql.internal.Field;
|
import de.steamwar.sql.internal.Field;
|
||||||
import de.steamwar.sql.internal.SelectStatement;
|
import de.steamwar.sql.internal.SelectStatement;
|
||||||
|
import de.steamwar.sql.internal.Statement;
|
||||||
import de.steamwar.sql.internal.Table;
|
import de.steamwar.sql.internal.Table;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@ -33,11 +34,25 @@ public class CheckedSchematic {
|
|||||||
|
|
||||||
private static final Table<CheckedSchematic> table = new Table<>(CheckedSchematic.class);
|
private static final Table<CheckedSchematic> table = new Table<>(CheckedSchematic.class);
|
||||||
private static final SelectStatement<CheckedSchematic> statusOfNode = new SelectStatement<>(table, "SELECT * FROM CheckedSchematic WHERE NodeId = ? AND DeclineReason != 'Prüfvorgang abgebrochen' ORDER BY EndTime DESC");
|
private static final SelectStatement<CheckedSchematic> statusOfNode = new SelectStatement<>(table, "SELECT * FROM CheckedSchematic WHERE NodeId = ? AND DeclineReason != 'Prüfvorgang abgebrochen' ORDER BY EndTime DESC");
|
||||||
|
private static final SelectStatement<CheckedSchematic> nodeHistory = new SelectStatement<>(table, "SELECT * FROM CheckedSchematic WHERE NodeId = ? AND DeclineReason != '' AND DeclineReason != 'Prüfvorgang abgebrochen' ORDER BY EndTime DESC");
|
||||||
|
private static final Statement insert = table.insertAll();
|
||||||
|
|
||||||
|
public static void create(int nodeId, String name, int owner, int validator, Timestamp startTime, Timestamp endTime, String reason){
|
||||||
|
insert.update(nodeId, owner, name, validator, startTime, endTime, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void create(SchematicNode node, int validator, Timestamp startTime, Timestamp endTime, String reason){
|
||||||
|
create(node.getId(), node.getName(), node.getOwner(), validator, startTime, endTime, reason);
|
||||||
|
}
|
||||||
|
|
||||||
public static List<CheckedSchematic> getLastDeclinedOfNode(int node){
|
public static List<CheckedSchematic> getLastDeclinedOfNode(int node){
|
||||||
return statusOfNode.listSelect(node);
|
return statusOfNode.listSelect(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<CheckedSchematic> previousChecks(SchematicNode node) {
|
||||||
|
return nodeHistory.listSelect(node.getId());
|
||||||
|
}
|
||||||
|
|
||||||
@Field(nullable = true)
|
@Field(nullable = true)
|
||||||
private final Integer nodeId;
|
private final Integer nodeId;
|
||||||
@Field
|
@Field
|
||||||
|
@ -33,6 +33,8 @@ import java.util.List;
|
|||||||
public class Event {
|
public class Event {
|
||||||
|
|
||||||
private static final Table<Event> table = new Table<>(Event.class);
|
private static final Table<Event> table = new Table<>(Event.class);
|
||||||
|
|
||||||
|
private static final SelectStatement<Event> byCurrent = new SelectStatement<>(table, "SELECT * FROM Event WHERE Start < now() AND End > now()");
|
||||||
private static final SelectStatement<Event> byId = table.select(Table.PRIMARY);
|
private static final SelectStatement<Event> byId = table.select(Table.PRIMARY);
|
||||||
private static final SelectStatement<Event> allShort = new SelectStatement<>(table, "SELECT * FROM Event");
|
private static final SelectStatement<Event> allShort = new SelectStatement<>(table, "SELECT * FROM Event");
|
||||||
private static final Statement create = table.insertFields(true, "eventName", "deadline", "start", "end", "maximumTeamMembers", "publicSchemsOnly", "spectateSystem");
|
private static final Statement create = table.insertFields(true, "eventName", "deadline", "start", "end", "maximumTeamMembers", "publicSchemsOnly", "spectateSystem");
|
||||||
|
@ -30,11 +30,19 @@ import lombok.Setter;
|
|||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static java.time.temporal.ChronoUnit.SECONDS;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class EventFight {
|
public class EventFight implements Comparable<EventFight> {
|
||||||
|
|
||||||
private static final Table<EventFight> table = new Table<>(EventFight.class);
|
private static final Table<EventFight> table = new Table<>(EventFight.class);
|
||||||
private static final SelectStatement<EventFight> byId = table.select(Table.PRIMARY);
|
private static final SelectStatement<EventFight> byId = table.select(Table.PRIMARY);
|
||||||
|
private static final SelectStatement<EventFight> allComing = new SelectStatement<>(table, "SELECT * FROM EventFight WHERE StartTime > now() ORDER BY StartTime ASC");
|
||||||
|
private static final SelectStatement<EventFight> event = new SelectStatement<>(table, "SELECT * FROM EventFight WHERE EventID = ? ORDER BY StartTime ASC");
|
||||||
|
private static final Statement reschedule = table.update(Table.PRIMARY, "StartTime");
|
||||||
private static final Statement setResult = table.update(Table.PRIMARY, "Ergebnis");
|
private static final Statement setResult = table.update(Table.PRIMARY, "Ergebnis");
|
||||||
private static final Statement setFight = table.update(Table.PRIMARY, "Fight");
|
private static final Statement setFight = table.update(Table.PRIMARY, "Fight");
|
||||||
private static final SelectStatement<EventFight> byEvent = table.selectFields("eventID");
|
private static final SelectStatement<EventFight> byEvent = table.selectFields("eventID");
|
||||||
@ -42,6 +50,8 @@ public class EventFight {
|
|||||||
private static final Statement create = table.insertFields(true, "eventID", "startTime", "spielModus", "map", "teamBlue", "teamRed", "kampfleiter");
|
private static final Statement create = table.insertFields(true, "eventID", "startTime", "spielModus", "map", "teamBlue", "teamRed", "kampfleiter");
|
||||||
private static final Statement delete = table.delete(Table.PRIMARY);
|
private static final Statement delete = table.delete(Table.PRIMARY);
|
||||||
|
|
||||||
|
private static final Queue<EventFight> fights = new PriorityQueue<>();
|
||||||
|
|
||||||
public static EventFight get(int fightID) {
|
public static EventFight get(int fightID) {
|
||||||
return byId.select(fightID);
|
return byId.select(fightID);
|
||||||
}
|
}
|
||||||
|
@ -20,24 +20,49 @@
|
|||||||
package de.steamwar.sql;
|
package de.steamwar.sql;
|
||||||
|
|
||||||
import de.steamwar.sql.internal.Field;
|
import de.steamwar.sql.internal.Field;
|
||||||
|
import de.steamwar.sql.internal.SelectStatement;
|
||||||
import de.steamwar.sql.internal.Statement;
|
import de.steamwar.sql.internal.Statement;
|
||||||
import de.steamwar.sql.internal.Table;
|
import de.steamwar.sql.internal.Table;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class Fight {
|
public class Fight {
|
||||||
|
|
||||||
private static final Table<Fight> table = new Table<>(Fight.class);
|
private static final Table<Fight> table = new Table<>(Fight.class);
|
||||||
|
private static final SelectStatement<Fight> getPage = new SelectStatement<>(table, "SELECT f.*, (b.NodeId IS NULL OR b.AllowReplay) AND (r.NodeId IS NULL OR r.AllowReplay) AS ReplayAllowed, (SELECT COUNT(1) FROM Replay WHERE Replay.FightID = f.FightID) as ReplayAvailable FROM Fight f LEFT OUTER JOIN SchematicNode b ON f.BlueSchem = b.NodeId LEFT OUTER JOIN SchematicNode r ON f.RedSchem = r.NodeId ORDER BY FightID DESC LIMIT ?, ?");
|
||||||
private static final Statement insert = table.insertFields(true, "GameMode", "Server", "StartTime", "Duration", "BlueLeader", "RedLeader", "BlueSchem", "RedSchem", "Win", "WinCondition");
|
private static final Statement insert = table.insertFields(true, "GameMode", "Server", "StartTime", "Duration", "BlueLeader", "RedLeader", "BlueSchem", "RedSchem", "Win", "WinCondition");
|
||||||
|
|
||||||
|
public static List<Fight> getPage(int page, int elementsPerPage) {
|
||||||
|
List<Fight> fights = getPage.listSelect(page * elementsPerPage, elementsPerPage);
|
||||||
|
|
||||||
|
List<FightPlayer> fightPlayers = FightPlayer.batchGet(fights.stream().map(f -> f.fightID));
|
||||||
|
for(Fight fight : fights) {
|
||||||
|
fight.initPlayers(fightPlayers);
|
||||||
|
}
|
||||||
|
|
||||||
|
SteamwarUser.batchCache(fightPlayers.stream().map(FightPlayer::getUserID).collect(Collectors.toSet()));
|
||||||
|
return fights;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int create(String gamemode, String server, Timestamp starttime, int duration, int blueleader, int redleader, Integer blueschem, Integer redschem, int win, String wincondition){
|
||||||
|
return insert.insertGetKey(gamemode, server, starttime, duration, blueleader, redleader, blueschem, redschem, win, wincondition);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
@Field(keys = {Table.PRIMARY}, autoincrement = true)
|
@Field(keys = {Table.PRIMARY}, autoincrement = true)
|
||||||
private final int fightID;
|
private final int fightID;
|
||||||
@Field
|
@Field
|
||||||
private final String gameMode;
|
private final String gameMode;
|
||||||
|
@Getter
|
||||||
@Field
|
@Field
|
||||||
private final String server;
|
private final String server;
|
||||||
|
@Getter
|
||||||
@Field
|
@Field
|
||||||
private final Timestamp startTime;
|
private final Timestamp startTime;
|
||||||
@Field
|
@Field
|
||||||
@ -50,12 +75,50 @@ public class Fight {
|
|||||||
private final Integer blueSchem;
|
private final Integer blueSchem;
|
||||||
@Field(nullable = true)
|
@Field(nullable = true)
|
||||||
private final Integer redSchem;
|
private final Integer redSchem;
|
||||||
|
@Getter
|
||||||
@Field
|
@Field
|
||||||
private final int win;
|
private final int win;
|
||||||
@Field
|
@Field
|
||||||
private final String wincondition;
|
private final String wincondition;
|
||||||
|
@Field // Virtual field for easy select
|
||||||
|
private final boolean replayAllowed;
|
||||||
|
@Field // Virtual field for easy select
|
||||||
|
private final boolean replayAvailable;
|
||||||
|
|
||||||
public static int create(String gamemode, String server, Timestamp starttime, int duration, int blueleader, int redleader, Integer blueschem, Integer redschem, int win, String wincondition){
|
@Getter
|
||||||
return insert.insertGetKey(gamemode, server, starttime, duration, blueleader, redleader, blueschem, redschem, win, wincondition);
|
private final List<FightPlayer> bluePlayers = new ArrayList<>();
|
||||||
|
@Getter
|
||||||
|
private final List<FightPlayer> redPlayers = new ArrayList<>();
|
||||||
|
|
||||||
|
public SchematicType getSchemType() {
|
||||||
|
return SchematicType.fromDB(gameMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SteamwarUser getBlueLeader() {
|
||||||
|
return SteamwarUser.get(blueLeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SteamwarUser getRedLeader() {
|
||||||
|
return SteamwarUser.get(redLeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean replayAllowed() {
|
||||||
|
return replayExists() && replayAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean replayExists() {
|
||||||
|
return getSchemType() != null && replayAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initPlayers(List<FightPlayer> fightPlayers) {
|
||||||
|
for(FightPlayer fp : fightPlayers) {
|
||||||
|
if(fp.getFightID() != fightID)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(fp.getTeam() == 1)
|
||||||
|
bluePlayers.add(fp);
|
||||||
|
else
|
||||||
|
redPlayers.add(fp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,20 +20,30 @@
|
|||||||
package de.steamwar.sql;
|
package de.steamwar.sql;
|
||||||
|
|
||||||
import de.steamwar.sql.internal.Field;
|
import de.steamwar.sql.internal.Field;
|
||||||
|
import de.steamwar.sql.internal.SelectStatement;
|
||||||
import de.steamwar.sql.internal.Statement;
|
import de.steamwar.sql.internal.Statement;
|
||||||
import de.steamwar.sql.internal.Table;
|
import de.steamwar.sql.internal.Table;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class FightPlayer {
|
public class FightPlayer {
|
||||||
|
|
||||||
private static final Table<FightPlayer> table = new Table<>(FightPlayer.class);
|
private static final Table<FightPlayer> table = new Table<>(FightPlayer.class);
|
||||||
private static final Statement create = table.insertAll();
|
private static final Statement create = table.insertAll();
|
||||||
|
private static final SelectStatement<FightPlayer> batchGet = new SelectStatement<>(table, "SELECT * FROM FightPlayer WHERE FightID IN ?");
|
||||||
|
|
||||||
|
@Getter
|
||||||
@Field(keys = {Table.PRIMARY})
|
@Field(keys = {Table.PRIMARY})
|
||||||
private final int fightID;
|
private final int fightID;
|
||||||
|
@Getter
|
||||||
@Field(keys = {Table.PRIMARY})
|
@Field(keys = {Table.PRIMARY})
|
||||||
private final int userID;
|
private final int userID;
|
||||||
|
@Getter
|
||||||
@Field
|
@Field
|
||||||
private final int team;
|
private final int team;
|
||||||
@Field
|
@Field
|
||||||
@ -46,4 +56,10 @@ public class FightPlayer {
|
|||||||
public static void create(int fightID, int userID, boolean blue, String kit, int kills, boolean isOut) {
|
public static void create(int fightID, int userID, boolean blue, String kit, int kills, boolean isOut) {
|
||||||
create.update(fightID, userID, blue ? 1 : 2, kit, kills, isOut);
|
create.update(fightID, userID, blue ? 1 : 2, kit, kills, isOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<FightPlayer> batchGet(Stream<Integer> fightIds) {
|
||||||
|
try (SelectStatement<FightPlayer> batch = new SelectStatement<>(table, "SELECT * FROM FightPlayer WHERE FightID IN (" + fightIds.map(Object::toString).collect(Collectors.joining(", ")) + ")")) {
|
||||||
|
return batch.listSelect();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
59
src/de/steamwar/sql/IgnoreSystem.java
Normale Datei
59
src/de/steamwar/sql/IgnoreSystem.java
Normale Datei
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.sql;
|
||||||
|
|
||||||
|
import de.steamwar.sql.internal.Field;
|
||||||
|
import de.steamwar.sql.internal.SelectStatement;
|
||||||
|
import de.steamwar.sql.internal.Statement;
|
||||||
|
import de.steamwar.sql.internal.Table;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class IgnoreSystem {
|
||||||
|
|
||||||
|
private static final Table<IgnoreSystem> table = new Table<>(IgnoreSystem.class, "IgnoredPlayers");
|
||||||
|
private static final SelectStatement<IgnoreSystem> select = table.select(Table.PRIMARY);
|
||||||
|
private static final Statement insert = table.insertAll();
|
||||||
|
private static final Statement delete = table.delete(Table.PRIMARY);
|
||||||
|
|
||||||
|
@Field(keys = {Table.PRIMARY})
|
||||||
|
private final int ignorer;
|
||||||
|
@Field(keys = {Table.PRIMARY})
|
||||||
|
private final int ignored;
|
||||||
|
|
||||||
|
public static boolean isIgnored(UUID ignorer, UUID ignored){
|
||||||
|
return isIgnored(SteamwarUser.get(ignorer), SteamwarUser.get(ignored));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isIgnored(SteamwarUser ignorer, SteamwarUser ignored) {
|
||||||
|
return select.select(ResultSet::next, ignorer.getId(), ignored.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ignore(SteamwarUser ignorer, SteamwarUser ignored) {
|
||||||
|
insert.update(ignorer.getId(), ignored.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void unIgnore(SteamwarUser ignorer, SteamwarUser ignored) {
|
||||||
|
delete.update(ignorer.getId(), ignored.getId());
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
package de.steamwar.sql;
|
package de.steamwar.sql;
|
||||||
|
|
||||||
import de.steamwar.sql.internal.*;
|
import de.steamwar.sql.internal.*;
|
||||||
@ -53,10 +72,19 @@ public class Mod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public enum ModType {
|
public enum ModType {
|
||||||
UNKLASSIFIED,
|
UNKLASSIFIED("7"),
|
||||||
GREEN,
|
GREEN("a"),
|
||||||
YELLOW,
|
YELLOW("e"),
|
||||||
RED,
|
RED("c"),
|
||||||
YOUTUBER_ONLY;
|
YOUTUBER_ONLY("6");
|
||||||
|
|
||||||
|
ModType(String colorcode) {
|
||||||
|
this.colorcode = colorcode;
|
||||||
|
}
|
||||||
|
private final String colorcode;
|
||||||
|
|
||||||
|
public String getColorCode() {
|
||||||
|
return colorcode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
92
src/de/steamwar/sql/NodeData.java
Normale Datei
92
src/de/steamwar/sql/NodeData.java
Normale Datei
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.sql;
|
||||||
|
|
||||||
|
import de.steamwar.sql.internal.*;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class NodeData {
|
||||||
|
|
||||||
|
static {
|
||||||
|
new SqlTypeMapper<>(PipedInputStream.class, "BLOB", (rs, identifier) -> { throw new SecurityException("PipedInputStream is write only datatype"); }, PreparedStatement::setBinaryStream);
|
||||||
|
new SqlTypeMapper<>(ByteArrayInputStream.class, "BLOB", (rs, identifier) -> { throw new SecurityException("ByteArrayInputStream is write only datatype"); }, PreparedStatement::setBinaryStream);
|
||||||
|
new SqlTypeMapper<>(BufferedInputStream.class, "BLOB", (rs, identifier) -> { throw new SecurityException("BufferedInputStream is write only datatype"); }, PreparedStatement::setBinaryStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Table<NodeData> table = new Table<>(NodeData.class);
|
||||||
|
|
||||||
|
private static final Statement updateDatabase = new Statement("INSERT INTO NodeData(NodeId, NodeFormat, SchemData) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE NodeFormat = VALUES(NodeFormat), SchemData = VALUES(SchemData)");
|
||||||
|
private static final Statement selSchemData = new Statement("SELECT SchemData FROM NodeData WHERE NodeId = ?");
|
||||||
|
|
||||||
|
private static final SelectStatement<NodeData> get = table.select(Table.PRIMARY);
|
||||||
|
|
||||||
|
public static NodeData get(SchematicNode node) {
|
||||||
|
if(node.isDir())
|
||||||
|
throw new IllegalArgumentException("Node is a directory");
|
||||||
|
return get.select(rs -> {
|
||||||
|
if(rs.next()) {
|
||||||
|
return new NodeData(node.getId(), rs.getBoolean("NodeFormat"));
|
||||||
|
} else {
|
||||||
|
return new NodeData(node.getId(), false);
|
||||||
|
}
|
||||||
|
}, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Field(keys = {Table.PRIMARY})
|
||||||
|
private final int nodeId;
|
||||||
|
|
||||||
|
@Field
|
||||||
|
private boolean nodeFormat;
|
||||||
|
|
||||||
|
public InputStream schemData() throws IOException {
|
||||||
|
try {
|
||||||
|
return selSchemData.select(rs -> {
|
||||||
|
rs.next();
|
||||||
|
InputStream schemData = rs.getBinaryStream("SchemData");
|
||||||
|
try {
|
||||||
|
if(rs.wasNull() || schemData.available() == 0) {
|
||||||
|
throw new SecurityException("SchemData is null");
|
||||||
|
}
|
||||||
|
return new GZIPInputStream(schemData);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new SecurityException("SchemData is wrong", e);
|
||||||
|
}
|
||||||
|
}, nodeId);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveFromStream(InputStream blob, boolean newFormat) {
|
||||||
|
updateDatabase.update(nodeId, newFormat, blob);
|
||||||
|
nodeFormat = newFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getNodeFormat() {
|
||||||
|
return nodeFormat;
|
||||||
|
}
|
||||||
|
}
|
@ -26,6 +26,7 @@ import de.steamwar.sql.internal.Table;
|
|||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@ -39,13 +40,16 @@ public class NodeMember {
|
|||||||
private static final SelectStatement<NodeMember> getNodeMember = table.select(Table.PRIMARY);
|
private static final SelectStatement<NodeMember> getNodeMember = table.select(Table.PRIMARY);
|
||||||
private static final SelectStatement<NodeMember> getNodeMembers = table.selectFields("NodeId");
|
private static final SelectStatement<NodeMember> getNodeMembers = table.selectFields("NodeId");
|
||||||
private static final SelectStatement<NodeMember> getSchematics = table.selectFields("UserId");
|
private static final SelectStatement<NodeMember> getSchematics = table.selectFields("UserId");
|
||||||
private static final Statement create = table.insertAll();
|
private static final Statement create = table.insert(Table.PRIMARY);
|
||||||
private static final Statement delete = table.delete(Table.PRIMARY);
|
private static final Statement delete = table.delete(Table.PRIMARY);
|
||||||
|
private static final Statement updateParent = table.update(Table.PRIMARY, "ParentId");
|
||||||
|
|
||||||
@Field(keys = {Table.PRIMARY})
|
@Field(keys = {Table.PRIMARY})
|
||||||
private final int nodeId;
|
private final int nodeId;
|
||||||
@Field(keys = {Table.PRIMARY})
|
@Field(keys = {Table.PRIMARY})
|
||||||
private final int userId;
|
private final int userId;
|
||||||
|
@Field(nullable = true, def = "null")
|
||||||
|
private Integer parentId;
|
||||||
|
|
||||||
public int getNode() {
|
public int getNode() {
|
||||||
return nodeId;
|
return nodeId;
|
||||||
@ -55,13 +59,17 @@ public class NodeMember {
|
|||||||
return userId;
|
return userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<Integer> getParent() {
|
||||||
|
return Optional.ofNullable(parentId);
|
||||||
|
}
|
||||||
|
|
||||||
public void delete() {
|
public void delete() {
|
||||||
delete.update(nodeId, userId);
|
delete.update(nodeId, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static NodeMember createNodeMember(int node, int member) {
|
public static NodeMember createNodeMember(int node, int member) {
|
||||||
create.update(node, member);
|
create.update(node, member);
|
||||||
return new NodeMember(node, member);
|
return new NodeMember(node, member, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static NodeMember getNodeMember(int node, int member) {
|
public static NodeMember getNodeMember(int node, int member) {
|
||||||
@ -75,4 +83,9 @@ public class NodeMember {
|
|||||||
public static Set<NodeMember> getSchematics(int member) {
|
public static Set<NodeMember> getSchematics(int member) {
|
||||||
return new HashSet<>(getSchematics.listSelect(member));
|
return new HashSet<>(getSchematics.listSelect(member));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setParentId(Integer parentId) {
|
||||||
|
this.parentId = parentId;
|
||||||
|
updateParent.update(this.parentId, nodeId, userId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
77
src/de/steamwar/sql/PollAnswer.java
Normale Datei
77
src/de/steamwar/sql/PollAnswer.java
Normale Datei
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.sql;
|
||||||
|
|
||||||
|
import de.steamwar.sql.internal.Field;
|
||||||
|
import de.steamwar.sql.internal.SelectStatement;
|
||||||
|
import de.steamwar.sql.internal.Statement;
|
||||||
|
import de.steamwar.sql.internal.Table;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class PollAnswer {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private static String currentPoll;
|
||||||
|
|
||||||
|
private static final Table<PollAnswer> table = new Table<>(PollAnswer.class);
|
||||||
|
|
||||||
|
private static final SelectStatement<PollAnswer> get = table.select(Table.PRIMARY);
|
||||||
|
private static final Statement getResults = new Statement("SELECT Count(UserID) AS Times, Answer FROM PollAnswer WHERE Question = ? GROUP BY Answer ORDER BY Times ASC");
|
||||||
|
private static final Statement insert = table.insertAll();
|
||||||
|
|
||||||
|
@Field(keys = {Table.PRIMARY})
|
||||||
|
private final int userID;
|
||||||
|
@Field(keys = {Table.PRIMARY})
|
||||||
|
private final String question;
|
||||||
|
@Field(def = "0")
|
||||||
|
private int answer;
|
||||||
|
|
||||||
|
public static PollAnswer get(int userID) {
|
||||||
|
PollAnswer answer = get.select(userID, currentPoll);
|
||||||
|
if(answer == null)
|
||||||
|
return new PollAnswer(userID, currentPoll, 0);
|
||||||
|
return answer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<Integer, Integer> getCurrentResults() {
|
||||||
|
return getResults.select(rs -> {
|
||||||
|
Map<Integer, Integer> retMap = new HashMap<>();
|
||||||
|
while (rs.next())
|
||||||
|
retMap.put(rs.getInt("Answer")-1, rs.getInt("Times"));
|
||||||
|
return retMap;
|
||||||
|
}, currentPoll);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasAnswered(){
|
||||||
|
return answer != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAnswer(int answer){
|
||||||
|
this.answer = answer;
|
||||||
|
insert.update(userID, question, answer);
|
||||||
|
}
|
||||||
|
}
|
@ -19,16 +19,16 @@
|
|||||||
|
|
||||||
package de.steamwar.sql;
|
package de.steamwar.sql;
|
||||||
|
|
||||||
import de.steamwar.sql.internal.Field;
|
import de.steamwar.sql.internal.*;
|
||||||
import de.steamwar.sql.internal.SelectStatement;
|
|
||||||
import de.steamwar.sql.internal.SqlTypeMapper;
|
|
||||||
import de.steamwar.sql.internal.Table;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
|
import java.time.Instant;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -40,13 +40,48 @@ public class Punishment {
|
|||||||
SqlTypeMapper.nameEnumMapper(PunishmentType.class);
|
SqlTypeMapper.nameEnumMapper(PunishmentType.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final Timestamp PERMA_TIME = Timestamp.from(Instant.ofEpochSecond(946674800));
|
||||||
|
|
||||||
private static final Table<Punishment> table = new Table<>(Punishment.class, "Punishments");
|
private static final Table<Punishment> table = new Table<>(Punishment.class, "Punishments");
|
||||||
private static final SelectStatement<Punishment> getPunishments = new SelectStatement<>(table, "SELECT * FROM Punishments WHERE PunishmentId IN (SELECT MAX(PunishmentId) FROM Punishments WHERE UserId = ? GROUP BY Type)");
|
private static final SelectStatement<Punishment> getPunishments = new SelectStatement<>(table, "SELECT * FROM Punishments WHERE PunishmentId IN (SELECT MAX(PunishmentId) FROM Punishments WHERE UserId = ? GROUP BY Type)");
|
||||||
private static final SelectStatement<Punishment> getPunishment = new SelectStatement<>(table, "SELECT * FROM Punishments WHERE UserId = ? AND Type = ? ORDER BY PunishmentId DESC LIMIT 1");
|
private static final SelectStatement<Punishment> getPunishment = new SelectStatement<>(table, "SELECT * FROM Punishments WHERE UserId = ? AND Type = ? ORDER BY PunishmentId DESC LIMIT 1");
|
||||||
|
private static final SelectStatement<Punishment> getAllPunishments = new SelectStatement<>(table, "SELECT * FROM Punishments WHERE UserId = ? ORDER BY `PunishmentId` DESC");
|
||||||
|
private static final Statement insert = table.insertFields(true, "UserId", "Punisher", "Type", "EndTime", "Perma", "Reason");
|
||||||
|
|
||||||
|
public static Punishment getPunishmentOfPlayer(int user, PunishmentType type) {
|
||||||
|
return getPunishment.select(user, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<PunishmentType, Punishment> getPunishmentsOfPlayer(int user) {
|
||||||
|
return getPunishments.listSelect(user).stream().collect(Collectors.toMap(Punishment::getType, punishment -> punishment));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Punishment> getAllPunishmentsOfPlayer(int user) {
|
||||||
|
return getAllPunishments.listSelect(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isPunished(SteamwarUser user, Punishment.PunishmentType type, Consumer<Punishment> callback) {
|
||||||
|
Punishment punishment = Punishment.getPunishmentOfPlayer(user.getId(), type);
|
||||||
|
if(punishment == null || !punishment.isCurrent()) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
callback.accept(punishment);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Punishment createPunishment(int user, int executor, PunishmentType type, String reason, Timestamp endTime, boolean perma) {
|
||||||
|
if(perma && !endTime.equals(PERMA_TIME)) {
|
||||||
|
throw new IllegalArgumentException("Permanent punishments must have an end time of `Punishment.PERMA_TIME`");
|
||||||
|
}
|
||||||
|
int punishmentId = insert.insertGetKey(user, executor, type.name(), endTime, perma, reason);
|
||||||
|
return new Punishment(punishmentId, user, executor, type, Timestamp.from(Instant.now()), endTime, perma, reason);
|
||||||
|
}
|
||||||
|
|
||||||
@Field(keys = {Table.PRIMARY}, autoincrement = true)
|
@Field(keys = {Table.PRIMARY}, autoincrement = true)
|
||||||
private final int punishmentId;
|
private final int punishmentId;
|
||||||
@Field
|
@Field
|
||||||
|
@Getter
|
||||||
private final int userId;
|
private final int userId;
|
||||||
@Field
|
@Field
|
||||||
@Getter
|
@Getter
|
||||||
@ -67,24 +102,6 @@ public class Punishment {
|
|||||||
@Getter
|
@Getter
|
||||||
private final String reason;
|
private final String reason;
|
||||||
|
|
||||||
public static Punishment getPunishmentOfPlayer(int user, PunishmentType type) {
|
|
||||||
return getPunishment.select(user, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Map<PunishmentType, Punishment> getPunishmentsOfPlayer(int user) {
|
|
||||||
return getPunishments.listSelect(user).stream().collect(Collectors.toMap(Punishment::getType, punishment -> punishment));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isPunished(SteamwarUser user, Punishment.PunishmentType type, Consumer<Punishment> callback) {
|
|
||||||
Punishment punishment = Punishment.getPunishmentOfPlayer(user.getId(), type);
|
|
||||||
if(punishment == null || !punishment.isCurrent()) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
callback.accept(punishment);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated // Not multiling, misleading title
|
@Deprecated // Not multiling, misleading title
|
||||||
public String getBantime(Timestamp endTime, boolean perma) {
|
public String getBantime(Timestamp endTime, boolean perma) {
|
||||||
if (perma) {
|
if (perma) {
|
||||||
@ -94,15 +111,12 @@ public class Punishment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getUserId() {
|
|
||||||
return userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCurrent() {
|
public boolean isCurrent() {
|
||||||
return isPerma() || getEndTime().after(new Date());
|
return isPerma() || getEndTime().after(new Date());
|
||||||
}
|
}
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
|
@RequiredArgsConstructor
|
||||||
@Getter
|
@Getter
|
||||||
public enum PunishmentType {
|
public enum PunishmentType {
|
||||||
Ban(false, "BAN_TEAM", "BAN_PERMA", "BAN_UNTIL", "UNBAN_ERROR", "UNBAN"),
|
Ban(false, "BAN_TEAM", "BAN_PERMA", "BAN_UNTIL", "UNBAN_ERROR", "UNBAN"),
|
||||||
@ -110,7 +124,10 @@ public class Punishment {
|
|||||||
NoSchemReceiving(false, "NOSCHEMRECEIVING_TEAM", "NOSCHEMRECEIVING_PERMA", "NOSCHEMRECEIVING_UNTIL", "UNNOSCHEMRECEIVING_ERROR", "UNNOSCHEMRECEIVING"),
|
NoSchemReceiving(false, "NOSCHEMRECEIVING_TEAM", "NOSCHEMRECEIVING_PERMA", "NOSCHEMRECEIVING_UNTIL", "UNNOSCHEMRECEIVING_ERROR", "UNNOSCHEMRECEIVING"),
|
||||||
NoSchemSharing(false, "NOSCHEMSHARING_TEAM", "NOSCHEMSHARING_PERMA", "NOSCHEMSHARING_UNTIL", "UNNOSCHEMSHARING_ERROR", "UNNOSCHEMSHARING"),
|
NoSchemSharing(false, "NOSCHEMSHARING_TEAM", "NOSCHEMSHARING_PERMA", "NOSCHEMSHARING_UNTIL", "UNNOSCHEMSHARING_ERROR", "UNNOSCHEMSHARING"),
|
||||||
NoSchemSubmitting(true, "NOSCHEMSUBMITTING_TEAM", "NOSCHEMSUBMITTING_PERMA", "NOSCHEMSUBMITTING_UNTIL", "UNNOSCHEMSUBMITTING_ERROR", "UNNOSCHEMSUBMITTING"),
|
NoSchemSubmitting(true, "NOSCHEMSUBMITTING_TEAM", "NOSCHEMSUBMITTING_PERMA", "NOSCHEMSUBMITTING_UNTIL", "UNNOSCHEMSUBMITTING_ERROR", "UNNOSCHEMSUBMITTING"),
|
||||||
NoDevServer(true, "NODEVSERVER_TEAM", "NODEVSERVER_PERMA", "NODEVSERVER_UNTIL", "UNNODEVSERVER_ERROR", "UNNODEVSERVER");
|
NoDevServer(true, "NODEVSERVER_TEAM", "NODEVSERVER_PERMA", "NODEVSERVER_UNTIL", "UNNODEVSERVER_ERROR", "UNNODEVSERVER"),
|
||||||
|
NoFightServer(false, "NOFIGHTSERVER_TEAM", "NOFIGHTSERVER_PERMA", "NOFIGHTSERVER_UNTIL", "UNNOFIGHTSERVER_ERROR", "UNNOFIGHTSERVER"),
|
||||||
|
NoTeamServer(true, "NOTEAMSERVER_TEAM", "NOTEAMSERVER_PERMA", "NOTEAMSERVER_UNTIL", "UNNOTEAMSERVER_ERROR", "UNNOTEAMSERVER"),
|
||||||
|
Note(false, "NOTE_TEAM", null, null, null, null, true);
|
||||||
|
|
||||||
private final boolean needsAdmin;
|
private final boolean needsAdmin;
|
||||||
private final String teamMessage;
|
private final String teamMessage;
|
||||||
@ -118,5 +135,6 @@ public class Punishment {
|
|||||||
private final String playerMessageUntil;
|
private final String playerMessageUntil;
|
||||||
private final String usageNotPunished;
|
private final String usageNotPunished;
|
||||||
private final String unpunishmentMessage;
|
private final String unpunishmentMessage;
|
||||||
|
private boolean multi = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,14 +21,31 @@ package de.steamwar.sql;
|
|||||||
|
|
||||||
import de.steamwar.sql.internal.Field;
|
import de.steamwar.sql.internal.Field;
|
||||||
import de.steamwar.sql.internal.SelectStatement;
|
import de.steamwar.sql.internal.SelectStatement;
|
||||||
|
import de.steamwar.sql.internal.Statement;
|
||||||
import de.steamwar.sql.internal.Table;
|
import de.steamwar.sql.internal.Table;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class SchemElo {
|
public class SchemElo {
|
||||||
|
private static final int ELO_DEFAULT = 1000;
|
||||||
|
|
||||||
private static final Table<SchemElo> table = new Table<>(SchemElo.class);
|
private static final Table<SchemElo> table = new Table<>(SchemElo.class);
|
||||||
private static final SelectStatement<SchemElo> select = table.select(Table.PRIMARY);
|
private static final SelectStatement<SchemElo> select = table.select(Table.PRIMARY);
|
||||||
|
private static final Statement setElo = table.insertAll();
|
||||||
|
|
||||||
|
public static int getElo(SchematicNode node, int season) {
|
||||||
|
SchemElo elo = select.select(node, season);
|
||||||
|
return elo != null ? elo.elo : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getCurrentElo(int schemID) {
|
||||||
|
SchemElo elo = select.select(schemID, Season.getSeason());
|
||||||
|
return elo != null ? elo.elo : ELO_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setElo(int schemID, int elo) {
|
||||||
|
setElo.update(schemID, elo, Season.getSeason());
|
||||||
|
}
|
||||||
|
|
||||||
@Field(keys = {Table.PRIMARY})
|
@Field(keys = {Table.PRIMARY})
|
||||||
private final int schemId;
|
private final int schemId;
|
||||||
@ -36,9 +53,4 @@ public class SchemElo {
|
|||||||
private final int elo;
|
private final int elo;
|
||||||
@Field(keys = {Table.PRIMARY})
|
@Field(keys = {Table.PRIMARY})
|
||||||
private final int season;
|
private final int season;
|
||||||
|
|
||||||
public static int getElo(SchematicNode node, int season) {
|
|
||||||
SchemElo elo = select.select(node, season);
|
|
||||||
return elo != null ? elo.elo : 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -21,16 +21,13 @@ package de.steamwar.sql;
|
|||||||
|
|
||||||
import de.steamwar.sql.internal.*;
|
import de.steamwar.sql.internal.*;
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class SchematicNode {
|
public class SchematicNode {
|
||||||
|
|
||||||
@ -43,34 +40,27 @@ public class SchematicNode {
|
|||||||
TAB_CACHE.clear();
|
TAB_CACHE.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String[] fields = {"NodeId", "NodeOwner", "NodeName", "ParentNode", "LastUpdate", "NodeItem", "NodeType", "NodeRank", "ReplaceColor", "AllowReplay", "NodeFormat"};
|
private static final String nodeSelector = "SELECT NodeId, NodeOwner, NodeOwner AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode ";
|
||||||
private static String nodeSelectCreator(String itemPrefix) {
|
|
||||||
return "SELECT " + Arrays.stream(fields).map(s -> itemPrefix + s).collect(Collectors.joining(", ")) + " FROM SchematicNode ";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Table<SchematicNode> table = new Table<>(SchematicNode.class);
|
private static final Table<SchematicNode> table = new Table<>(SchematicNode.class);
|
||||||
private static final Statement create = table.insertFields(true, "NodeOwner", "NodeName", "ParentNode", "NodeItem", "NodeType");
|
private static final Statement create = table.insertFields(true, "NodeOwner", "NodeName", "ParentNode", "NodeItem", "NodeType");
|
||||||
private static final Statement update = table.update(Table.PRIMARY, "NodeName", "ParentNode", "NodeItem", "NodeType", "NodeRank", "ReplaceColor", "AllowReplay", "NodeFormat");
|
private static final Statement update = table.update(Table.PRIMARY, "NodeName", "ParentNode", "NodeItem", "NodeType", "NodeRank", "ReplaceColor", "AllowReplay");
|
||||||
private static final Statement delete = table.delete(Table.PRIMARY);
|
private static final Statement delete = table.delete(Table.PRIMARY);
|
||||||
|
|
||||||
private static final SelectStatement<SchematicNode> byId = table.select(Table.PRIMARY);
|
private static final SelectStatement<SchematicNode> byId = new SelectStatement<>(table, nodeSelector + "WHERE NodeId = ?");
|
||||||
private static final SelectStatement<SchematicNode> byOwnerNameParent = table.select("OwnerNameParent");
|
private static final SelectStatement<SchematicNode> byOwnerNameParent = new SelectStatement<>(table, nodeSelector + "WHERE NodeOwner = ? AND NodeName = ? AND ParentNode " + Statement.NULL_SAFE_EQUALS + "?");
|
||||||
private static final SelectStatement<SchematicNode> byOwnerNameParent_null = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE NodeOwner = ? AND NodeName = ? AND ParentNode is NULL");
|
private static final SelectStatement<SchematicNode> byParent = new SelectStatement<>(table, nodeSelector + "WHERE ParentNode" + Statement.NULL_SAFE_EQUALS + "? ORDER BY NodeName");
|
||||||
private static final SelectStatement<SchematicNode> byParent = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE ParentNode = ? ORDER BY NodeName");
|
private static final SelectStatement<SchematicNode> dirsByParent = new SelectStatement<>(table, nodeSelector + "WHERE ParentNode" + Statement.NULL_SAFE_EQUALS + "? AND NodeType is NULL ORDER BY NodeName");
|
||||||
private static final SelectStatement<SchematicNode> byParent_null = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE ParentNode is NULL ORDER BY NodeName");
|
private static final SelectStatement<SchematicNode> byOwnerType = new SelectStatement<>(table, nodeSelector + "WHERE NodeOwner = ? AND NodeType = ? ORDER BY NodeName");
|
||||||
private static final SelectStatement<SchematicNode> dirsByParent = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE ParentNode = ? AND NodeType is NULL ORDER BY NodeName");
|
private static final SelectStatement<SchematicNode> byType = new SelectStatement<>(table, nodeSelector + "WHERE NodeType = ? ORDER BY NodeName");
|
||||||
private static final SelectStatement<SchematicNode> dirsByParent_null = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE ParentNode is NULL AND NodeType is NULL ORDER BY NodeName");
|
private static final SelectStatement<SchematicNode> all = new SelectStatement<>(table, "SELECT * FROM EffectiveSchematicNode WHERE EffectiveOwner = ? ORDER BY NodeName");
|
||||||
private static final SelectStatement<SchematicNode> byParentName = table.selectFields("NodeName", "ParentNode");
|
private static final SelectStatement<SchematicNode> list = new SelectStatement<>(table, "SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId " + Statement.NULL_SAFE_EQUALS + "? AND NM.UserId = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE (? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?) ORDER BY NodeName");
|
||||||
private static final SelectStatement<SchematicNode> byParentName_null = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE NodeName = ? AND ParentNode is NULL");
|
private static final SelectStatement<SchematicNode> byParentName = new SelectStatement<>(table, "SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId " + Statement.NULL_SAFE_EQUALS + "? AND NM.UserId = ? AND SchematicNode.NodeName = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE ((? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?)) AND NodeName = ?");
|
||||||
private static final SelectStatement<SchematicNode> accessibleByUserTypeParent = new SelectStatement<>(table, "WITH RECURSIVE RSNB AS (WITH RECURSIVE RSN as (" + nodeSelectCreator("s.") + "s LEFT JOIN NodeMember n ON s.NodeId = n.NodeId WHERE (s.NodeOwner = ? OR n.UserId = ?) GROUP BY s.NodeId UNION " + nodeSelectCreator("SN.") + "AS SN, RSN WHERE SN.ParentNode = RSN.NodeId) SELECT * FROM RSN WHERE NodeType = ? UNION " + nodeSelectCreator("SN.") + "AS SN, RSNB WHERE SN.NodeId = RSNB.ParentNode)SELECT * FROM RSNB WHERE ParentNode = ? ORDER BY NodeName");
|
private static final SelectStatement<SchematicNode> schematicAccessibleForUser = new SelectStatement<>(table, "SELECT COUNT(DISTINCT NodeId) FROM EffectiveSchematicNode WHERE EffectiveOwner = ? AND NodeId = ?");
|
||||||
private static final SelectStatement<SchematicNode> accessibleByUserTypeParent_Null = new SelectStatement<>(table, "WITH RECURSIVE RSNB AS (WITH RECURSIVE RSN as (" + nodeSelectCreator("s.") + "s LEFT JOIN NodeMember n ON s.NodeId = n.NodeId WHERE (s.NodeOwner = ? OR n.UserId = ?) GROUP BY s.NodeId UNION " + nodeSelectCreator("SN.") + "AS SN, RSN WHERE SN.ParentNode = RSN.NodeId) SELECT * FROM RSN WHERE NodeType = ? UNION " + nodeSelectCreator("SN.") + "AS SN, RSNB WHERE SN.NodeId = RSNB.ParentNode)SELECT * FROM RSNB WHERE ParentNode is null ORDER BY NodeName");
|
private static final SelectStatement<SchematicNode> accessibleByUserTypeInParent = new SelectStatement<>(table, "WITH RECURSIVE RSN AS (SELECT NodeId, ParentNode FROM EffectiveSchematicNode WHERE NodeType = ? AND EffectiveOwner = ? UNION SELECT SN.NodeId, SN.ParentNode FROM RSN, EffectiveSchematicNode SN WHERE SN.NodeId = RSN.ParentNode AND EffectiveOwner = ?) SELECT SN.NodeId, SN.NodeOwner, ? AS EffectiveOwner, SN.NodeName, RSN.ParentNode, SN.LastUpdate, SN.NodeItem, SN.NodeType, SN.NodeRank, SN.ReplaceColor, SN.AllowReplay FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId WHERE RSN.ParentNode" + Statement.NULL_SAFE_EQUALS + "?");
|
||||||
private static final SelectStatement<SchematicNode> accessibleByUserType = new SelectStatement<>(table, "WITH RECURSIVE RSN as (" + nodeSelectCreator("s.") + "s LEFT JOIN NodeMember n ON s.NodeId = n.NodeId WHERE (s.NodeOwner = ? OR n.UserId = ?) GROUP BY s.NodeId UNION " + nodeSelectCreator("SN.") + "AS SN, RSN WHERE SN.ParentNode = RSN.NodeId) SELECT * FROM RSN WHERE NodeType = ? ORDER BY NodeName");
|
private static final SelectStatement<SchematicNode> accessibleByUserType = new SelectStatement<>(table, "SELECT * FROM EffectiveSchematicNode WHERE EffectiveOwner = ? AND NodeType = ?");
|
||||||
private static final SelectStatement<SchematicNode> byOwnerType = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE NodeOwner = ? AND NodeType = ? ORDER BY NodeName");
|
private static final SelectStatement<SchematicNode> byIdAndUser = new SelectStatement<>(table, "SELECT NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE NodeId = ?");
|
||||||
private static final SelectStatement<SchematicNode> byType = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE NodeType = ? ORDER BY NodeName");
|
private static final SelectStatement<SchematicNode> allParentsOfNode = new SelectStatement<>(table, "WITH RECURSIVE R AS (SELECT NodeId, ParentNode FROM EffectiveSchematicNode WHERE NodeId = ? AND EffectiveOwner = ? UNION SELECT E.NodeId, E.ParentNode FROM R, EffectiveSchematicNode E WHERE R.ParentNode = E.NodeId AND E.EffectiveOwner = ?) SELECT SN.NodeId, SN.NodeOwner, ? AS EffectiveOwner, SN.NodeName, R.ParentNode, SN.LastUpdate, SN.NodeItem, SN.NodeType, SN.NodeRank, SN.ReplaceColor, SN.AllowReplay FROM R INNER JOIN SchematicNode SN ON SN.NodeId = R.NodeId");
|
||||||
private static final SelectStatement<SchematicNode> accessibleByUser = new SelectStatement<>(table, nodeSelectCreator("s.") + "s LEFT JOIN NodeMember n ON s.NodeId = n.NodeId WHERE (s.NodeOwner = ? OR n.UserId = ?) AND ((s.NodeOwner = ? AND s.ParentNode IS NULL) OR NOT s.NodeOwner = ?) GROUP BY s.NodeId ORDER BY s.NodeName");
|
|
||||||
private static final Statement schematicAccessibleForUser = new Statement("WITH RECURSIVE RSN AS (" + nodeSelectCreator("") + "WHERE NodeId = ? UNION " + nodeSelectCreator("SN.") + "SN, RSN WHERE RSN.ParentNode = SN.NodeId) SELECT COUNT(RSN.NodeId) AS `Accessible` FROM RSN LEFT Join NodeMember NM On NM.NodeId = RSN.NodeId WHERE NodeOwner = ? OR UserId = ? LIMIT 1");
|
|
||||||
private static final SelectStatement<SchematicNode> allAccessibleByUser = new SelectStatement<>(table, "WITH RECURSIVE RSN as (" + nodeSelectCreator("s.") + "s LEFT JOIN NodeMember n ON s.NodeId = n.NodeId WHERE (s.NodeOwner = ? OR n.UserId = ?) GROUP BY s.NodeId UNION " + nodeSelectCreator("SN.") + "AS SN, RSN WHERE SN.ParentNode = RSN.NodeId) SELECT * FROM RSN ORDER BY NodeName");
|
|
||||||
private static final SelectStatement<SchematicNode> allParentsOfNode = new SelectStatement<>(table, "WITH RECURSIVE RSN AS (" + nodeSelectCreator("") + "WHERE NodeId = ? UNION " + nodeSelectCreator("SN.") + "SN, RSN WHERE RSN.ParentNode = SN.NodeId) SELECT * FROM RSN ORDER BY NodeName");
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
NodeMember.init();
|
NodeMember.init();
|
||||||
@ -80,6 +70,9 @@ public class SchematicNode {
|
|||||||
private final int nodeId;
|
private final int nodeId;
|
||||||
@Field(keys = {"OwnerNameParent"})
|
@Field(keys = {"OwnerNameParent"})
|
||||||
private final int nodeOwner;
|
private final int nodeOwner;
|
||||||
|
@Field(def = "0")
|
||||||
|
@Getter
|
||||||
|
private final int effectiveOwner;
|
||||||
@Field(keys = {"OwnerNameParent"})
|
@Field(keys = {"OwnerNameParent"})
|
||||||
private String nodeName;
|
private String nodeName;
|
||||||
@Field(keys = {"OwnerNameParent"}, nullable = true)
|
@Field(keys = {"OwnerNameParent"}, nullable = true)
|
||||||
@ -96,15 +89,13 @@ public class SchematicNode {
|
|||||||
private boolean replaceColor;
|
private boolean replaceColor;
|
||||||
@Field(def = "1")
|
@Field(def = "1")
|
||||||
private boolean allowReplay;
|
private boolean allowReplay;
|
||||||
@Setter(AccessLevel.PACKAGE)
|
|
||||||
@Field(def = "1")
|
|
||||||
private boolean nodeFormat;
|
|
||||||
|
|
||||||
private final Map<Integer, String> brCache = new HashMap<>();
|
private String brCache;
|
||||||
|
|
||||||
public SchematicNode(
|
public SchematicNode(
|
||||||
int nodeId,
|
int nodeId,
|
||||||
int nodeOwner,
|
int nodeOwner,
|
||||||
|
int effectiveOwner,
|
||||||
String nodeName,
|
String nodeName,
|
||||||
Integer parentNode,
|
Integer parentNode,
|
||||||
Timestamp lastUpdate,
|
Timestamp lastUpdate,
|
||||||
@ -112,11 +103,11 @@ public class SchematicNode {
|
|||||||
SchematicType nodeType,
|
SchematicType nodeType,
|
||||||
int nodeRank,
|
int nodeRank,
|
||||||
boolean replaceColor,
|
boolean replaceColor,
|
||||||
boolean allowReplay,
|
boolean allowReplay
|
||||||
boolean nodeFormat
|
|
||||||
) {
|
) {
|
||||||
this.nodeId = nodeId;
|
this.nodeId = nodeId;
|
||||||
this.nodeOwner = nodeOwner;
|
this.nodeOwner = nodeOwner;
|
||||||
|
this.effectiveOwner = effectiveOwner;
|
||||||
this.nodeName = nodeName;
|
this.nodeName = nodeName;
|
||||||
this.parentNode = parentNode;
|
this.parentNode = parentNode;
|
||||||
this.nodeItem = nodeItem;
|
this.nodeItem = nodeItem;
|
||||||
@ -125,7 +116,54 @@ public class SchematicNode {
|
|||||||
this.nodeRank = nodeRank;
|
this.nodeRank = nodeRank;
|
||||||
this.replaceColor = replaceColor;
|
this.replaceColor = replaceColor;
|
||||||
this.allowReplay = allowReplay;
|
this.allowReplay = allowReplay;
|
||||||
this.nodeFormat = nodeFormat;
|
}
|
||||||
|
|
||||||
|
public static List<SchematicNode> getAll(SteamwarUser user) {
|
||||||
|
return all.listSelect(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<Integer, List<SchematicNode>> getAllMap(SteamwarUser user) {
|
||||||
|
return map(getAll(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<SchematicNode> list(SteamwarUser user, Integer schematicId) {
|
||||||
|
return list.listSelect(user, schematicId, user, user, schematicId, user, schematicId, schematicId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SchematicNode byParentName(SteamwarUser user, Integer schematicId, String name) {
|
||||||
|
return byParentName.select(user, schematicId, user, name, user, schematicId, user, schematicId, schematicId, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<SchematicNode> accessibleByUserType(SteamwarUser user, SchematicType type) {
|
||||||
|
return accessibleByUserType.listSelect(user, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<Integer, List<SchematicNode>> accessibleByUserTypeMap(SteamwarUser user, SchematicType type) {
|
||||||
|
return map(accessibleByUserType(user, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean schematicAccessibleForUser(SteamwarUser user, Integer schematicId) {
|
||||||
|
return schematicAccessibleForUser.select(user, schematicId) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<SchematicNode> accessibleByUserTypeParent(SteamwarUser user, SchematicType type, Integer parentId) {
|
||||||
|
return accessibleByUserTypeInParent.listSelect(type, user, user, user, parentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SchematicNode byIdAndUser(SteamwarUser user, Integer id) {
|
||||||
|
return byIdAndUser.select(user, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<SchematicNode> parentsOfNode(SteamwarUser user, Integer id) {
|
||||||
|
return allParentsOfNode.listSelect(id, user, user, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<Integer, List<SchematicNode>> map(List<SchematicNode> in) {
|
||||||
|
Map<Integer, List<SchematicNode>> map = new HashMap<>();
|
||||||
|
for (SchematicNode effectiveSchematicNode : in) {
|
||||||
|
map.computeIfAbsent(effectiveSchematicNode.getOptionalParent().orElse(0), k -> new ArrayList<>()).add(effectiveSchematicNode);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SchematicNode createSchematic(int owner, String name, Integer parent) {
|
public static SchematicNode createSchematic(int owner, String name, Integer parent) {
|
||||||
@ -148,8 +186,6 @@ public class SchematicNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static SchematicNode getSchematicNode(int owner, String name, Integer parent) {
|
public static SchematicNode getSchematicNode(int owner, String name, Integer parent) {
|
||||||
if (parent == null || parent == 0)
|
|
||||||
return byOwnerNameParent_null.select(owner, name);
|
|
||||||
return byOwnerNameParent.select(owner, name, parent);
|
return byOwnerNameParent.select(owner, name, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,19 +194,10 @@ public class SchematicNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static List<SchematicNode> getSchematicNodeInNode(Integer parent) {
|
public static List<SchematicNode> getSchematicNodeInNode(Integer parent) {
|
||||||
if(parent == null || parent == 0) {
|
|
||||||
rootWarning();
|
|
||||||
return byParent_null.listSelect();
|
|
||||||
}
|
|
||||||
|
|
||||||
return byParent.listSelect(parent);
|
return byParent.listSelect(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<SchematicNode> getSchematicDirectoryInNode(Integer parent) {
|
public static List<SchematicNode> getSchematicDirectoryInNode(Integer parent) {
|
||||||
if(parent == null || parent == 0) {
|
|
||||||
rootWarning();
|
|
||||||
return dirsByParent_null.listSelect();
|
|
||||||
}
|
|
||||||
return dirsByParent.listSelect(parent);
|
return dirsByParent.listSelect(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,10 +212,6 @@ public class SchematicNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static SchematicNode getSchematicNode(String name, Integer parent) {
|
public static SchematicNode getSchematicNode(String name, Integer parent) {
|
||||||
if(parent == null || parent == 0) {
|
|
||||||
rootWarning();
|
|
||||||
return byParentName_null.select(name);
|
|
||||||
}
|
|
||||||
return byParentName.select(name, parent);
|
return byParentName.select(name, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,13 +220,11 @@ public class SchematicNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static List<SchematicNode> getAccessibleSchematicsOfTypeInParent(int owner, String schemType, Integer parent) {
|
public static List<SchematicNode> getAccessibleSchematicsOfTypeInParent(int owner, String schemType, Integer parent) {
|
||||||
if(parent == null || parent == 0)
|
return accessibleByUserTypeParent(SteamwarUser.get(owner), SchematicType.fromDB(schemType), parent);
|
||||||
return accessibleByUserTypeParent_Null.listSelect(owner, owner, schemType);
|
|
||||||
return accessibleByUserTypeParent.listSelect(owner, owner, schemType, parent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<SchematicNode> getAllAccessibleSchematicsOfType(int user, String schemType) {
|
public static List<SchematicNode> getAllAccessibleSchematicsOfType(int user, String schemType) {
|
||||||
return accessibleByUserType.listSelect(user, user, schemType);
|
return accessibleByUserType(SteamwarUser.get(user), SchematicType.fromDB(schemType));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<SchematicNode> getAllSchematicsOfType(int owner, String schemType) {
|
public static List<SchematicNode> getAllSchematicsOfType(int owner, String schemType) {
|
||||||
@ -233,21 +254,14 @@ public class SchematicNode {
|
|||||||
return finalList;
|
return finalList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public static List<SchematicNode> getSchematicsAccessibleByUser(int user, Integer parent) {
|
public static List<SchematicNode> getSchematicsAccessibleByUser(int user, Integer parent) {
|
||||||
if (parent == null || parent == 0)
|
return list(SteamwarUser.get(user), parent);
|
||||||
return accessibleByUser.listSelect(user, user, user, user);
|
|
||||||
|
|
||||||
if(schematicAccessibleForUser.select(rs -> {
|
|
||||||
rs.next();
|
|
||||||
return rs.getInt("Accessible") > 0;
|
|
||||||
}, parent, user, user))
|
|
||||||
return getSchematicNodeInNode(parent);
|
|
||||||
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public static List<SchematicNode> getAllSchematicsAccessibleByUser(int user) {
|
public static List<SchematicNode> getAllSchematicsAccessibleByUser(int user) {
|
||||||
return allAccessibleByUser.listSelect(user, user);
|
return getAll(SteamwarUser.get(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<SchematicNode> getAllParentsOfNode(SchematicNode node) {
|
public static List<SchematicNode> getAllParentsOfNode(SchematicNode node) {
|
||||||
@ -262,33 +276,30 @@ public class SchematicNode {
|
|||||||
if (s.startsWith("/")) {
|
if (s.startsWith("/")) {
|
||||||
s = s.substring(1);
|
s = s.substring(1);
|
||||||
}
|
}
|
||||||
|
if (s.endsWith("/")) {
|
||||||
|
s = s.substring(0, s.length() - 1);
|
||||||
|
}
|
||||||
if (s.isEmpty()) {
|
if (s.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (s.contains("/")) {
|
if (s.contains("/")) {
|
||||||
String[] layers = s.split("/");
|
String[] layers = s.split("/");
|
||||||
SchematicNode currentNode = null;
|
Optional<SchematicNode> currentNode = Optional.ofNullable(SchematicNode.byParentName(user, null, layers[0]));
|
||||||
for (int i = 0; i < layers.length; i++) {
|
for (int i = 1; i < layers.length; i++) {
|
||||||
int finalI = i;
|
int finalI = i;
|
||||||
Optional<SchematicNode> node;
|
Optional<SchematicNode> node = currentNode.map(effectiveSchematicNode -> SchematicNode.byParentName(user, effectiveSchematicNode.getId(), layers[finalI]));
|
||||||
if (currentNode == null) {
|
|
||||||
node = SchematicNode.getSchematicsAccessibleByUser(user.getId(), 0).stream().filter(node1 -> node1.getName().equals(layers[finalI])).findAny();
|
|
||||||
} else {
|
|
||||||
node = Optional.ofNullable(SchematicNode.getSchematicNode(layers[i], currentNode.getId()));
|
|
||||||
}
|
|
||||||
if (!node.isPresent()) {
|
if (!node.isPresent()) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
currentNode = node.get();
|
currentNode = node;
|
||||||
if (!currentNode.isDir() && i != layers.length - 1) {
|
if (!currentNode.map(SchematicNode::isDir).orElse(false) && i != layers.length - 1) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return currentNode;
|
return currentNode.orElse(null);
|
||||||
} else {
|
} else {
|
||||||
String finalS = s;
|
return SchematicNode.byParentName(user, null, s);
|
||||||
return SchematicNode.getSchematicsAccessibleByUser(user.getId(), 0).stream().filter(node1 -> node1.getName().equals(finalS)).findAny().orElse(null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,11 +317,6 @@ public class SchematicNode {
|
|||||||
return finalList;
|
return finalList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public static Integer countNodes() {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getId() {
|
public int getId() {
|
||||||
return nodeId;
|
return nodeId;
|
||||||
}
|
}
|
||||||
@ -332,6 +338,10 @@ public class SchematicNode {
|
|||||||
return parentNode;
|
return parentNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<Integer> getOptionalParent() {
|
||||||
|
return Optional.ofNullable(parentNode);
|
||||||
|
}
|
||||||
|
|
||||||
public void setParent(Integer parent) {
|
public void setParent(Integer parent) {
|
||||||
this.parentNode = parent;
|
this.parentNode = parent;
|
||||||
updateDB();
|
updateDB();
|
||||||
@ -366,10 +376,11 @@ public class SchematicNode {
|
|||||||
return nodeType == null;
|
return nodeType == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public boolean getSchemFormat() {
|
public boolean getSchemFormat() {
|
||||||
if(isDir())
|
if(isDir())
|
||||||
throw new SecurityException("Node is Directory");
|
throw new SecurityException("Node is Directory");
|
||||||
return nodeFormat;
|
return NodeData.get(this).getNodeFormat();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getRank() {
|
public int getRank() {
|
||||||
@ -447,8 +458,7 @@ public class SchematicNode {
|
|||||||
|
|
||||||
private void updateDB() {
|
private void updateDB() {
|
||||||
this.lastUpdate = Timestamp.from(Instant.now());
|
this.lastUpdate = Timestamp.from(Instant.now());
|
||||||
update.update(nodeName, parentNode, nodeItem, nodeType, nodeRank, replaceColor, allowReplay, nodeFormat, nodeId);
|
update.update(nodeName, parentNode, nodeItem, nodeType, nodeRank, replaceColor, allowReplay, nodeId);
|
||||||
this.brCache.clear();
|
|
||||||
TAB_CACHE.clear();
|
TAB_CACHE.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -470,21 +480,29 @@ public class SchematicNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String generateBreadcrumbs(SteamwarUser user) {
|
public String generateBreadcrumbs(SteamwarUser user) {
|
||||||
return brCache.computeIfAbsent(user.getId(), integer -> generateBreadcrumbs("/", user));
|
return byIdAndUser(user, nodeId).generateBreadcrumbs();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String generateBreadcrumbs(String split, SteamwarUser user) {
|
public String generateBreadcrumbs(String split, SteamwarUser user) {
|
||||||
|
return byIdAndUser(user, nodeId).generateBreadcrumbs(split);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String generateBreadcrumbs() {
|
||||||
|
if(brCache == null) {
|
||||||
|
brCache = generateBreadcrumbs("/");
|
||||||
|
}
|
||||||
|
return brCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String generateBreadcrumbs(String split) {
|
||||||
StringBuilder builder = new StringBuilder(getName());
|
StringBuilder builder = new StringBuilder(getName());
|
||||||
SchematicNode currentNode = this;
|
Optional<SchematicNode> currentNode = Optional.of(this);
|
||||||
if (currentNode.isDir()) builder.append("/");
|
if(currentNode.map(SchematicNode::isDir).orElse(false)) {
|
||||||
final Set<NodeMember> nodeMembers = NodeMember.getSchematics(user.getId());
|
builder.append(split);
|
||||||
AtomicInteger i = new AtomicInteger();
|
}
|
||||||
i.set(currentNode.getId());
|
while (currentNode.isPresent()) {
|
||||||
while (currentNode.getParentNode() != null && nodeMembers.stream().noneMatch(nodeMember -> nodeMember.getNode() == i.get())) {
|
currentNode = currentNode.flatMap(schematicNode -> Optional.ofNullable(NodeMember.getNodeMember(schematicNode.getId(), effectiveOwner)).map(NodeMember::getParent).orElse(schematicNode.getOptionalParent())).map(SchematicNode::getSchematicNode);
|
||||||
currentNode = currentNode.getParentNode();
|
currentNode.ifPresent(node -> builder.insert(0, split).insert(0, node.getName()));
|
||||||
i.set(currentNode.getId());
|
|
||||||
builder.insert(0, split)
|
|
||||||
.insert(0, currentNode.getName());
|
|
||||||
}
|
}
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
@ -527,21 +545,16 @@ public class SchematicNode {
|
|||||||
if (s.contains("/")) {
|
if (s.contains("/")) {
|
||||||
String preTab = s.substring(0, s.lastIndexOf("/") + 1);
|
String preTab = s.substring(0, s.lastIndexOf("/") + 1);
|
||||||
SchematicNode pa = SchematicNode.getNodeFromPath(user, preTab);
|
SchematicNode pa = SchematicNode.getNodeFromPath(user, preTab);
|
||||||
if (pa == null) return Collections.emptyList();
|
if (pa == null) return new ArrayList<>();
|
||||||
List<SchematicNode> nodes = SchematicNode.getSchematicNodeInNode(pa);
|
List<SchematicNode> nodes = SchematicNode.list(user, pa.getId());
|
||||||
nodes.forEach(node -> list.add((sws ? "/" : "") + node.generateBreadcrumbs(user)));
|
String br = pa.generateBreadcrumbs();
|
||||||
|
nodes.forEach(node -> list.add((sws ? "/" : "") + br + node.getName() + (node.isDir() ? "/" : "")));
|
||||||
} else {
|
} else {
|
||||||
List<SchematicNode> nodes = SchematicNode.getSchematicsAccessibleByUser(user.getId(), 0);
|
List<SchematicNode> nodes = SchematicNode.list(user, null);
|
||||||
nodes.forEach(node -> list.add((sws ? "/" : "") + node.getName() + (node.isDir() ? "/" : "")));
|
nodes.forEach(node -> list.add((sws ? "/" : "") + node.getName() + (node.isDir() ? "/" : "")));
|
||||||
}
|
}
|
||||||
list.remove("//copy");
|
list.remove("//copy");
|
||||||
TAB_CACHE.computeIfAbsent(user.getId(), integer -> new HashMap<>()).putIfAbsent(cacheKey, list);
|
TAB_CACHE.computeIfAbsent(user.getId(), integer -> new HashMap<>()).putIfAbsent(cacheKey, list);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void rootWarning() {
|
|
||||||
ByteArrayOutputStream stacktraceOutput = new ByteArrayOutputStream();
|
|
||||||
new Throwable().printStackTrace(new PrintStream(stacktraceOutput));
|
|
||||||
SWException.log("PERFORMANCE!!! Getting all/weird subset of schematic nodes with parent NULL", stacktraceOutput.toString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
package de.steamwar.sql;
|
package de.steamwar.sql;
|
||||||
|
|
||||||
import de.steamwar.sql.internal.SqlTypeMapper;
|
import de.steamwar.sql.internal.SqlTypeMapper;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@ -51,17 +52,26 @@ public class SchematicType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
@Getter
|
||||||
private final String kuerzel;
|
private final String kuerzel;
|
||||||
private final Type type;
|
private final Type type;
|
||||||
private final SchematicType checkType;
|
private final SchematicType checkType;
|
||||||
|
@Getter
|
||||||
private final String material;
|
private final String material;
|
||||||
|
@Getter
|
||||||
|
private final Date deadline;
|
||||||
|
|
||||||
SchematicType(String name, String kuerzel, Type type, SchematicType checkType, String material){
|
SchematicType(String name, String kuerzel, Type type, SchematicType checkType, String material){
|
||||||
|
this(name, kuerzel, type, checkType, material, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
SchematicType(String name, String kuerzel, Type type, SchematicType checkType, String material, Date deadline){
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.kuerzel = kuerzel;
|
this.kuerzel = kuerzel;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.checkType = checkType;
|
this.checkType = checkType;
|
||||||
this.material = material;
|
this.material = material;
|
||||||
|
this.deadline = deadline;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAssignable(){
|
public boolean isAssignable(){
|
||||||
@ -88,14 +98,6 @@ public class SchematicType {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getKuerzel() {
|
|
||||||
return kuerzel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMaterial() {
|
|
||||||
return material;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toDB(){
|
public String toDB(){
|
||||||
return name.toLowerCase();
|
return name.toLowerCase();
|
||||||
}
|
}
|
||||||
|
45
src/de/steamwar/sql/Session.java
Normale Datei
45
src/de/steamwar/sql/Session.java
Normale Datei
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.sql;
|
||||||
|
|
||||||
|
import de.steamwar.sql.internal.Field;
|
||||||
|
import de.steamwar.sql.internal.Statement;
|
||||||
|
import de.steamwar.sql.internal.Table;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class Session {
|
||||||
|
|
||||||
|
private static final Table<Session> table = new Table<>(Session.class);
|
||||||
|
private static final Statement insert = table.insert(Table.PRIMARY);
|
||||||
|
|
||||||
|
public static void insertSession(int userID, Timestamp startTime){
|
||||||
|
insert.update(userID, startTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Field(keys = {Table.PRIMARY})
|
||||||
|
private int userId;
|
||||||
|
@Field(keys = {Table.PRIMARY})
|
||||||
|
private Timestamp startTime;
|
||||||
|
@Field(def = "CURRENT_TIMESTAMP")
|
||||||
|
private Timestamp endTime;
|
||||||
|
}
|
@ -22,7 +22,11 @@ package de.steamwar.sql;
|
|||||||
import de.steamwar.sql.internal.*;
|
import de.steamwar.sql.internal.*;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class SteamwarUser {
|
public class SteamwarUser {
|
||||||
|
|
||||||
@ -52,6 +56,9 @@ public class SteamwarUser {
|
|||||||
private static final Statement updateLeader = table.update(Table.PRIMARY, "Leader");
|
private static final Statement updateLeader = table.update(Table.PRIMARY, "Leader");
|
||||||
private static final Statement updateDiscord = table.update(Table.PRIMARY, "DiscordId");
|
private static final Statement updateDiscord = table.update(Table.PRIMARY, "DiscordId");
|
||||||
|
|
||||||
|
private static final Statement getPlaytime = new Statement("SELECT SUM(UNIX_TIMESTAMP(EndTime) - UNIX_TIMESTAMP(StartTime)) as Playtime FROM Session WHERE UserID = ?");
|
||||||
|
private static final Statement getFirstjoin = new Statement("SELECT MIN(StartTime) AS FirstJoin FROM Session WHERE UserID = ?");
|
||||||
|
|
||||||
private static final Map<Integer, SteamwarUser> usersById = new HashMap<>();
|
private static final Map<Integer, SteamwarUser> usersById = new HashMap<>();
|
||||||
private static final Map<UUID, SteamwarUser> usersByUUID = new HashMap<>();
|
private static final Map<UUID, SteamwarUser> usersByUUID = new HashMap<>();
|
||||||
private static final Map<String, SteamwarUser> usersByName = new HashMap<>();
|
private static final Map<String, SteamwarUser> usersByName = new HashMap<>();
|
||||||
@ -69,6 +76,83 @@ public class SteamwarUser {
|
|||||||
return;
|
return;
|
||||||
usersByName.remove(user.getUserName());
|
usersByName.remove(user.getUserName());
|
||||||
usersByUUID.remove(user.getUUID());
|
usersByUUID.remove(user.getUUID());
|
||||||
|
usersByDiscord.remove(user.getDiscordId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SteamwarUser get(String userName){
|
||||||
|
SteamwarUser user = usersByName.get(userName.toLowerCase());
|
||||||
|
if(user != null)
|
||||||
|
return user;
|
||||||
|
return loadPunishments(byName.select(userName));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SteamwarUser get(UUID uuid){
|
||||||
|
SteamwarUser user = usersByUUID.get(uuid);
|
||||||
|
if(user != null)
|
||||||
|
return user;
|
||||||
|
return loadPunishments(byUUID.select(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SteamwarUser get(int id) {
|
||||||
|
SteamwarUser user = usersById.get(id);
|
||||||
|
if(user != null)
|
||||||
|
return user;
|
||||||
|
return loadPunishments(byID.select(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SteamwarUser get(Long discordId) {
|
||||||
|
if(usersByDiscord.containsKey(discordId))
|
||||||
|
return usersByDiscord.get(discordId);
|
||||||
|
return loadPunishments(byDiscord.select(discordId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SteamwarUser getOrCreate(UUID uuid, String name, Consumer<UUID> newPlayer, BiConsumer<String, String> nameUpdate) {
|
||||||
|
SteamwarUser user = get(uuid);
|
||||||
|
|
||||||
|
if (user != null) {
|
||||||
|
if (!user.userName.equals(name)) {
|
||||||
|
updateName.update(name, user.id);
|
||||||
|
nameUpdate.accept(user.userName, name);
|
||||||
|
user.userName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return user;
|
||||||
|
} else {
|
||||||
|
insert.update(uuid, name);
|
||||||
|
newPlayer.accept(uuid);
|
||||||
|
return get(uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<SteamwarUser> getServerTeam() {
|
||||||
|
return loadPunishments(getServerTeam.listSelect());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<SteamwarUser> getTeam(int teamId) {
|
||||||
|
return loadPunishments(byTeam.listSelect(teamId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void batchCache(Set<Integer> ids) {
|
||||||
|
ids.removeIf(usersById::containsKey);
|
||||||
|
if(ids.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
try (SelectStatement<SteamwarUser> batch = new SelectStatement<>(table, "SELECT * FROM UserData WHERE id IN (" + ids.stream().map(Object::toString).collect(Collectors.joining(", ")) + ")")) {
|
||||||
|
loadPunishments(batch.listSelect());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<SteamwarUser> loadPunishments(List<SteamwarUser> users) {
|
||||||
|
users.forEach(user -> user.punishments = Punishment.getPunishmentsOfPlayer(user.getId()));
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SteamwarUser loadPunishments(SteamwarUser user) {
|
||||||
|
if(user == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
user.punishments = Punishment.getPunishmentsOfPlayer(user.getId());
|
||||||
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ -85,15 +169,19 @@ public class SteamwarUser {
|
|||||||
@Getter
|
@Getter
|
||||||
@Field(def = "0")
|
@Field(def = "0")
|
||||||
private int team;
|
private int team;
|
||||||
|
@Getter
|
||||||
@Field(def = "0")
|
@Field(def = "0")
|
||||||
private boolean leader;
|
private boolean leader;
|
||||||
@Field(nullable = true)
|
@Field(nullable = true)
|
||||||
private Locale locale;
|
private Locale locale;
|
||||||
@Field(def = "0")
|
@Field(def = "0")
|
||||||
private boolean manualLocale;
|
private boolean manualLocale;
|
||||||
|
@Getter
|
||||||
@Field(keys = {"discordId"}, nullable = true)
|
@Field(keys = {"discordId"}, nullable = true)
|
||||||
private Long discordId;
|
private Long discordId;
|
||||||
|
|
||||||
|
private Map<Punishment.PunishmentType, Punishment> punishments;
|
||||||
|
|
||||||
public SteamwarUser(int id, UUID uuid, String userName, UserGroup userGroup, int team, boolean leader, Locale locale, boolean manualLocale, Long discordId) {
|
public SteamwarUser(int id, UUID uuid, String userName, UserGroup userGroup, int team, boolean leader, Locale locale, boolean manualLocale, Long discordId) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.uuid = uuid;
|
this.uuid = uuid;
|
||||||
@ -123,6 +211,56 @@ public class SteamwarUser {
|
|||||||
return Locale.getDefault();
|
return Locale.getDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Punishment getPunishment(Punishment.PunishmentType type) {
|
||||||
|
return punishments.getOrDefault(type, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPunished(Punishment.PunishmentType punishment) {
|
||||||
|
if (!punishments.containsKey(punishment)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!punishments.get(punishment).isCurrent()) {
|
||||||
|
if (punishment == Punishment.PunishmentType.Ban) {
|
||||||
|
BannedUserIPs.unbanIPs(id);
|
||||||
|
}
|
||||||
|
punishments.remove(punishment);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getOnlinetime() {
|
||||||
|
return getPlaytime.select(rs -> {
|
||||||
|
if (rs.next() && rs.getBigDecimal("Playtime") != null)
|
||||||
|
return rs.getBigDecimal("Playtime").doubleValue();
|
||||||
|
return 0.0;
|
||||||
|
}, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Timestamp getFirstjoin() {
|
||||||
|
return getFirstjoin.select(rs -> {
|
||||||
|
if (rs.next())
|
||||||
|
return rs.getTimestamp("FirstJoin");
|
||||||
|
return null;
|
||||||
|
}, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void punish(Punishment.PunishmentType punishment, Timestamp time, String banReason, int from, boolean perma) {
|
||||||
|
punishments.remove(punishment);
|
||||||
|
punishments.put(punishment, Punishment.createPunishment(id, from, punishment, banReason, time, perma));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTeam(int team) {
|
||||||
|
this.team = team;
|
||||||
|
updateTeam.update(team, id);
|
||||||
|
setLeader(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLeader(boolean leader) {
|
||||||
|
this.leader = leader;
|
||||||
|
updateLeader.update(leader, id);
|
||||||
|
}
|
||||||
|
|
||||||
public void setLocale(Locale locale, boolean manualLocale) {
|
public void setLocale(Locale locale, boolean manualLocale) {
|
||||||
if (locale == null || (this.manualLocale && !manualLocale))
|
if (locale == null || (this.manualLocale && !manualLocale))
|
||||||
return;
|
return;
|
||||||
@ -132,18 +270,13 @@ public class SteamwarUser {
|
|||||||
updateLocale.update(locale.toLanguageTag(), manualLocale, id);
|
updateLocale.update(locale.toLanguageTag(), manualLocale, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SteamwarUser get(String userName){
|
public void setDiscordId(Long discordId) {
|
||||||
SteamwarUser user = usersByName.get(userName.toLowerCase());
|
usersByDiscord.remove(this.discordId);
|
||||||
if(user != null)
|
this.discordId = discordId;
|
||||||
return user;
|
updateDiscord.update(discordId, id);
|
||||||
return byName.select(userName);
|
if (discordId != null) {
|
||||||
}
|
usersByDiscord.put(discordId, this);
|
||||||
|
}
|
||||||
public static SteamwarUser get(UUID uuid){
|
|
||||||
SteamwarUser user = usersByUUID.get(uuid);
|
|
||||||
if(user != null)
|
|
||||||
return user;
|
|
||||||
return byUUID.select(uuid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SteamwarUser get(int id) {
|
public static SteamwarUser get(int id) {
|
||||||
|
@ -21,41 +21,65 @@ package de.steamwar.sql;
|
|||||||
|
|
||||||
import de.steamwar.sql.internal.Field;
|
import de.steamwar.sql.internal.Field;
|
||||||
import de.steamwar.sql.internal.SelectStatement;
|
import de.steamwar.sql.internal.SelectStatement;
|
||||||
|
import de.steamwar.sql.internal.Statement;
|
||||||
import de.steamwar.sql.internal.Table;
|
import de.steamwar.sql.internal.Table;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class Team {
|
public class Team {
|
||||||
|
|
||||||
private static final Table<Team> table = new Table<>(Team.class);
|
private static final Map<Integer, Team> teamCache = new HashMap<>();
|
||||||
private static final SelectStatement<Team> select = table.select(Table.PRIMARY);
|
|
||||||
private static final SelectStatement<Team> all = new SelectStatement(table, "SELECT * FROM Team");
|
|
||||||
|
|
||||||
@Field(keys = {Table.PRIMARY})
|
public static void clear() {
|
||||||
|
teamCache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Table<Team> table = new Table<>(Team.class);
|
||||||
|
private static final SelectStatement<Team> byId = table.select(Table.PRIMARY);
|
||||||
|
private static final SelectStatement<Team> byName = new SelectStatement<>(table, "SELECT * FROM Team WHERE (lower(TeamName) = ? OR lower(TeamKuerzel) = ?) AND NOT TeamDeleted");
|
||||||
|
private static final SelectStatement<Team> all = table.selectFields("TeamDeleted");
|
||||||
|
private static final Statement insert = table.insertFields("TeamKuerzel", "TeamName");
|
||||||
|
private static final Statement update = table.update(Table.PRIMARY, "TeamKuerzel", "TeamName", "TeamColor", "Address", "Port");
|
||||||
|
private static final Statement delete = table.update(Table.PRIMARY, "TeamDeleted");
|
||||||
|
private static final Statement getSize = new Statement("SELECT COUNT(id) FROM UserData WHERE Team = ?");
|
||||||
|
|
||||||
|
@Field(keys = {Table.PRIMARY}, autoincrement = true)
|
||||||
@Getter
|
@Getter
|
||||||
private final int teamId;
|
private final int teamId;
|
||||||
@Field
|
@Field
|
||||||
@Getter
|
@Getter
|
||||||
private final String teamKuerzel;
|
private String teamKuerzel;
|
||||||
@Field
|
@Field
|
||||||
@Getter
|
@Getter
|
||||||
private final String teamName;
|
private String teamName;
|
||||||
@Field(def = "'8'")
|
@Field(def = "'8'")
|
||||||
@Getter
|
@Getter
|
||||||
private final String teamColor;
|
private String teamColor;
|
||||||
|
@Field(nullable = true)
|
||||||
|
@Getter
|
||||||
|
private String address;
|
||||||
|
@Field(def = "'25565'")
|
||||||
|
@Getter
|
||||||
|
private int port;
|
||||||
|
@Field(def = "0")
|
||||||
|
private boolean teamDeleted;
|
||||||
|
|
||||||
private static final Team pub = new Team(0, "PUB", "Öffentlich", "8");
|
public static void create(String kuerzel, String name){
|
||||||
|
insert.update(kuerzel, name);
|
||||||
|
}
|
||||||
|
|
||||||
public static Team get(int id) {
|
public static Team get(int id) {
|
||||||
if(id == -1)
|
if(id == -1)
|
||||||
return new Team(-1, "?", "?", "8");
|
return new Team(-1, "?", "?", "8");
|
||||||
if(id == 0)
|
if(id == 0)
|
||||||
return pub;
|
return pub;
|
||||||
return select.select(id);
|
return byId.select(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Team> getAll() {
|
public static List<Team> getAll() {
|
||||||
@ -65,4 +89,47 @@ public class Team {
|
|||||||
public List<Integer> getMembers(){
|
public List<Integer> getMembers(){
|
||||||
return SteamwarUser.getTeam(teamId).stream().map(SteamwarUser::getId).collect(Collectors.toList());
|
return SteamwarUser.getTeam(teamId).stream().map(SteamwarUser::getId).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int size(){
|
||||||
|
return getSize.select(rs -> {
|
||||||
|
rs.next();
|
||||||
|
return rs.getInt("COUNT(id)");
|
||||||
|
}, teamId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disband(SteamwarUser user){
|
||||||
|
user.setLeader(false);
|
||||||
|
delete.update(true, teamId);
|
||||||
|
teamCache.remove(teamId);
|
||||||
|
TeamTeilnahme.deleteFuture(teamId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTeamKuerzel(String teamKuerzel) {
|
||||||
|
this.teamKuerzel = teamKuerzel;
|
||||||
|
updateDB();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTeamName(String teamName) {
|
||||||
|
this.teamName = teamName;
|
||||||
|
updateDB();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTeamColor(String teamColor) {
|
||||||
|
this.teamColor = teamColor;
|
||||||
|
updateDB();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddress(String address) {
|
||||||
|
this.address = address;
|
||||||
|
updateDB();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPort(int port) {
|
||||||
|
this.port = port;
|
||||||
|
updateDB();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDB(){
|
||||||
|
update.update(teamKuerzel, teamName, teamColor, address, port, teamId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ package de.steamwar.sql;
|
|||||||
|
|
||||||
import de.steamwar.sql.internal.Field;
|
import de.steamwar.sql.internal.Field;
|
||||||
import de.steamwar.sql.internal.SelectStatement;
|
import de.steamwar.sql.internal.SelectStatement;
|
||||||
|
import de.steamwar.sql.internal.Statement;
|
||||||
import de.steamwar.sql.internal.Table;
|
import de.steamwar.sql.internal.Table;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
@ -34,6 +35,9 @@ public class TeamTeilnahme {
|
|||||||
private static final SelectStatement<TeamTeilnahme> select = table.select(Table.PRIMARY);
|
private static final SelectStatement<TeamTeilnahme> select = table.select(Table.PRIMARY);
|
||||||
private static final SelectStatement<TeamTeilnahme> selectTeams = table.selectFields("EventID");
|
private static final SelectStatement<TeamTeilnahme> selectTeams = table.selectFields("EventID");
|
||||||
private static final SelectStatement<TeamTeilnahme> selectEvents = table.selectFields("TeamID");
|
private static final SelectStatement<TeamTeilnahme> selectEvents = table.selectFields("TeamID");
|
||||||
|
private static final Statement insert = table.insert(Table.PRIMARY);
|
||||||
|
private static final Statement delete = table.delete(Table.PRIMARY);
|
||||||
|
private static final Statement deleteFuture = new Statement("DELETE t FROM TeamTeilnahme t INNER JOIN Event e ON t.EventID = e.EventID WHERE t.TeamID = ? AND e.Start > NOW()");
|
||||||
|
|
||||||
@Field(keys = {Table.PRIMARY})
|
@Field(keys = {Table.PRIMARY})
|
||||||
private final int teamId;
|
private final int teamId;
|
||||||
@ -44,6 +48,18 @@ public class TeamTeilnahme {
|
|||||||
return select.select(teamID, eventID) != null;
|
return select.select(teamID, eventID) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void teilnehmen(int teamID, int eventID){
|
||||||
|
insert.update(teamID, eventID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void notTeilnehmen(int teamID, int eventID){
|
||||||
|
delete.update(teamID, eventID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void deleteFuture(int teamID) {
|
||||||
|
deleteFuture.update(teamID);
|
||||||
|
}
|
||||||
|
|
||||||
public static Set<Team> getTeams(int eventID){
|
public static Set<Team> getTeams(int eventID){
|
||||||
return selectTeams.listSelect(eventID).stream().map(tt -> Team.get(tt.teamId)).collect(Collectors.toSet()); // suboptimal performance (O(n) database queries)
|
return selectTeams.listSelect(eventID).stream().map(tt -> Team.get(tt.teamId)).collect(Collectors.toSet()); // suboptimal performance (O(n) database queries)
|
||||||
}
|
}
|
||||||
|
94
src/de/steamwar/sql/Tutorial.java
Normale Datei
94
src/de/steamwar/sql/Tutorial.java
Normale Datei
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.sql;
|
||||||
|
|
||||||
|
import de.steamwar.sql.internal.Field;
|
||||||
|
import de.steamwar.sql.internal.SelectStatement;
|
||||||
|
import de.steamwar.sql.internal.Statement;
|
||||||
|
import de.steamwar.sql.internal.Table;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class Tutorial {
|
||||||
|
|
||||||
|
private static final Table<Tutorial> table = new Table<>(Tutorial.class);
|
||||||
|
private static final SelectStatement<Tutorial> by_popularity = new SelectStatement<>(table, "SELECT t.*, AVG(r.Stars) AS Stars FROM Tutorial t LEFT OUTER JOIN TutorialRating r ON t.TutorialID = r.TutorialID WHERE t.Released = ? GROUP BY t.TutorialID ORDER BY SUM(r.Stars) DESC LIMIT ?, ?");
|
||||||
|
private static final SelectStatement<Tutorial> own = new SelectStatement<>(table, "SELECT t.*, AVG(r.Stars) AS Stars FROM Tutorial t LEFT OUTER JOIN TutorialRating r ON t.TutorialID = r.TutorialID WHERE t.Creator = ? GROUP BY t.TutorialID ORDER BY t.TutorialID ASC LIMIT ?, ?");
|
||||||
|
private static final SelectStatement<Tutorial> by_creator_name = new SelectStatement<>(table, "SELECT t.*, AVG(r.Stars) AS Stars FROM Tutorial t LEFT OUTER JOIN TutorialRating r ON t.TutorialID = r.TutorialID WHERE t.Creator = ? AND t.Name = ? GROUP BY t.TutorialID");
|
||||||
|
private static final SelectStatement<Tutorial> by_id = new SelectStatement<>(table, "SELECT t.*, AVG(r.Stars) AS Stars FROM Tutorial t LEFT OUTER JOIN TutorialRating r ON t.TutorialID = r.TutorialID WHERE t.TutorialID = ? GROUP BY t.TutorialID");
|
||||||
|
private static final Statement rate = new Statement("INSERT INTO TutorialRating (TutorialID, UserID, Stars) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE Stars = VALUES(Stars)");
|
||||||
|
private static final Statement create = new Statement("INSERT INTO Tutorial (Creator, Name, Item) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE Item = VALUES(Item), Released = 0");
|
||||||
|
private static final Statement release = table.update(Table.PRIMARY, "released");
|
||||||
|
private static final Statement delete = table.delete(Table.PRIMARY);
|
||||||
|
|
||||||
|
public static List<Tutorial> getPage(int page, int elementsPerPage, boolean released) {
|
||||||
|
List<Tutorial> tutorials = by_popularity.listSelect(released, page * elementsPerPage, elementsPerPage);
|
||||||
|
SteamwarUser.batchCache(tutorials.stream().map(tutorial -> tutorial.creator).collect(Collectors.toSet()));
|
||||||
|
return tutorials;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Tutorial> getOwn(int user, int page, int elementsPerPage) {
|
||||||
|
return own.listSelect(user, page * elementsPerPage, elementsPerPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Tutorial create(int creator, String name, String item) {
|
||||||
|
create.update(creator, name, item);
|
||||||
|
return by_creator_name.select(creator, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Tutorial get(int id) {
|
||||||
|
return by_id.select(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Field(keys = {Table.PRIMARY}, autoincrement = true)
|
||||||
|
private final int tutorialId;
|
||||||
|
@Getter
|
||||||
|
@Field(keys = {"CreatorName"})
|
||||||
|
private final int creator;
|
||||||
|
@Getter
|
||||||
|
@Field(keys = {"CreatorName"})
|
||||||
|
private final String name;
|
||||||
|
@Getter
|
||||||
|
@Field(def = "'BOOK'")
|
||||||
|
private final String item;
|
||||||
|
@Getter
|
||||||
|
@Field(def = "0")
|
||||||
|
private final boolean released;
|
||||||
|
@Getter
|
||||||
|
@Field(def = "0") // Not really a field, but necessary for select generation
|
||||||
|
private final double stars;
|
||||||
|
|
||||||
|
public void release() {
|
||||||
|
release.update(1, tutorialId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete() {
|
||||||
|
delete.update(tutorialId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void rate(int user, int rating) {
|
||||||
|
rate.update(tutorialId, user, rating);
|
||||||
|
}
|
||||||
|
}
|
178
src/de/steamwar/sql/UserElo.java
Normale Datei
178
src/de/steamwar/sql/UserElo.java
Normale Datei
@ -0,0 +1,178 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.sql;
|
||||||
|
|
||||||
|
import de.steamwar.sql.internal.Field;
|
||||||
|
import de.steamwar.sql.internal.SelectStatement;
|
||||||
|
import de.steamwar.sql.internal.Statement;
|
||||||
|
import de.steamwar.sql.internal.Table;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class UserElo {
|
||||||
|
private static final int ELO_DEFAULT = 1000;
|
||||||
|
|
||||||
|
private static final Map<String, Map<Integer, Optional<Integer>>> gameModeUserEloCache = new ConcurrentHashMap<>();
|
||||||
|
private static final Map<String, Integer> maxEloCache = new ConcurrentHashMap<>();
|
||||||
|
private static final Map<Integer, String> emblemCache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public static void clear() {
|
||||||
|
gameModeUserEloCache.clear();
|
||||||
|
maxEloCache.clear();
|
||||||
|
emblemCache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Table<UserElo> table = new Table<>(UserElo.class);
|
||||||
|
private static final SelectStatement<UserElo> getElo = table.select(Table.PRIMARY);
|
||||||
|
private static final Statement setElo = table.insertAll();
|
||||||
|
private static final Statement maxElo = new Statement("SELECT MAX(Elo) AS MaxElo FROM UserElo WHERE Season = ? AND GameMode = ?");
|
||||||
|
|
||||||
|
private static final Statement place = new Statement("SELECT COUNT(*) AS Place FROM UserElo WHERE GameMode = ? AND Elo > ? AND Season = ?");
|
||||||
|
private static final Statement fightsOfSeason = new Statement("SELECT COUNT(*) AS Fights FROM FightPlayer INNER JOIN Fight F on FightPlayer.FightID = F.FightID WHERE UserID = ? AND GameMode = ? AND UNIX_TIMESTAMP(StartTime) + Duration >= UNIX_TIMESTAMP(?)");
|
||||||
|
|
||||||
|
@Field(keys = {Table.PRIMARY})
|
||||||
|
private final int season;
|
||||||
|
@Field(keys = {Table.PRIMARY})
|
||||||
|
private final String gameMode;
|
||||||
|
@Field(keys = {Table.PRIMARY})
|
||||||
|
private final int userId;
|
||||||
|
@Field
|
||||||
|
private final int elo;
|
||||||
|
|
||||||
|
public static int getEloOrDefault(int userID, String gameMode) {
|
||||||
|
return getElo(userID, gameMode).orElse(ELO_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<Integer> getElo(int userID, String gameMode) {
|
||||||
|
return gameModeUserEloCache.computeIfAbsent(gameMode, gm -> new HashMap<>()).computeIfAbsent(userID, uid -> Optional.ofNullable(getElo.select(Season.getSeason(), gameMode, userID)).map(userElo -> userElo.elo));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getFightsOfSeason(int userID, String gameMode) {
|
||||||
|
return fightsOfSeason.select(rs -> {
|
||||||
|
if (rs.next())
|
||||||
|
return rs.getInt("Fights");
|
||||||
|
return 0;
|
||||||
|
}, userID, gameMode, Season.getSeasonStart());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getMaxElo(String gameMode) {
|
||||||
|
return maxEloCache.computeIfAbsent(gameMode, gm -> maxElo.select(rs -> {
|
||||||
|
if (rs.next())
|
||||||
|
return rs.getInt("MaxElo");
|
||||||
|
return 0;
|
||||||
|
}, Season.getSeason(), gameMode));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setElo(int userId, String gameMode, int elo) {
|
||||||
|
emblemCache.remove(userId);
|
||||||
|
|
||||||
|
Optional<Integer> oldElo = Optional.ofNullable(gameModeUserEloCache.computeIfAbsent(gameMode, gm -> new HashMap<>()).put(userId, Optional.of(elo))).orElse(Optional.empty());
|
||||||
|
int maxElo = getMaxElo(gameMode);
|
||||||
|
if (elo > maxElo || (oldElo.isPresent() && oldElo.get() == maxElo)) {
|
||||||
|
maxEloCache.remove(gameMode);
|
||||||
|
emblemCache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
setElo.update(Season.getSeason(), gameMode, userId, elo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getPlacement(int elo, String gameMode) {
|
||||||
|
return place.select(rs -> {
|
||||||
|
if (rs.next())
|
||||||
|
return rs.getInt("Place") + 1;
|
||||||
|
return -1;
|
||||||
|
}, gameMode, elo, Season.getSeason());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getEmblem(SteamwarUser user, List<String> rankedModes) {
|
||||||
|
return emblemCache.computeIfAbsent(user.getId(), userId -> {
|
||||||
|
switch(
|
||||||
|
rankedModes.stream().filter(
|
||||||
|
mode -> UserElo.getFightsOfSeason(user.getId(), mode) >= 10
|
||||||
|
).map(
|
||||||
|
mode -> getProgression(user.getId(), mode)
|
||||||
|
).max(Integer::compareTo).orElse(0)
|
||||||
|
) {
|
||||||
|
case 0:
|
||||||
|
return "";
|
||||||
|
case 1:
|
||||||
|
return "§7✧ ";
|
||||||
|
case 2:
|
||||||
|
return "§f✦ ";
|
||||||
|
case 3:
|
||||||
|
return "§e✶ ";
|
||||||
|
case 4:
|
||||||
|
return "§a✷ ";
|
||||||
|
case 5:
|
||||||
|
return "§b✸ ";
|
||||||
|
case 6:
|
||||||
|
return "§c✹ ";
|
||||||
|
case 7:
|
||||||
|
return "§5❂ ";
|
||||||
|
default:
|
||||||
|
throw new SecurityException("Progression out of range");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getEmblemProgression(String gameMode, int userId) {
|
||||||
|
switch (getProgression(userId, gameMode)) {
|
||||||
|
case 0:
|
||||||
|
return "§8✧ ✦ ✶ ✷ ✸ ✹ ❂";
|
||||||
|
case 1:
|
||||||
|
return "§7✧ §8✦ ✶ ✷ ✸ ✹ ❂";
|
||||||
|
case 2:
|
||||||
|
return "§8✧ §f✦ §8✶ ✷ ✸ ✹ ❂";
|
||||||
|
case 3:
|
||||||
|
return "§8✧ ✦ §e✶ §8✷ ✸ ✹ ❂";
|
||||||
|
case 4:
|
||||||
|
return "§8✧ ✦ ✶ §a✷ §8✸ ✹ ❂";
|
||||||
|
case 5:
|
||||||
|
return "§8✧ ✦ ✶ ✷ §b✸ §8✹ ❂";
|
||||||
|
case 6:
|
||||||
|
return "§8✧ ✦ ✶ ✷ ✸ §c✹ §8❂";
|
||||||
|
case 7:
|
||||||
|
return "§8✧ ✦ ✶ ✷ ✸ ✹ §5❂";
|
||||||
|
default:
|
||||||
|
throw new SecurityException("Progression is not in range");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getProgression(int userId, String gameMode) {
|
||||||
|
int elo = getElo(userId, gameMode).orElse(0);
|
||||||
|
if(elo == 0)
|
||||||
|
return 0;
|
||||||
|
int maxElo = getMaxElo(gameMode);
|
||||||
|
|
||||||
|
if (elo > maxElo * 0.99) return 7;
|
||||||
|
if (elo > maxElo * 0.97) return 6;
|
||||||
|
if (elo > maxElo * 0.94) return 5;
|
||||||
|
if (elo > maxElo * 0.88) return 4;
|
||||||
|
if (elo > maxElo * 0.76) return 3;
|
||||||
|
if (elo > maxElo * 0.51) return 2;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
(at your option) any later version.
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU Affero General Public License for more details.
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
You should have received a copy of the GNU Affero General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package de.steamwar.sql;
|
package de.steamwar.sql;
|
||||||
|
|
||||||
@ -24,22 +24,35 @@ import lombok.Getter;
|
|||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum UserGroup {
|
public enum UserGroup {
|
||||||
Admin("§4", "§e", true, true, true),
|
Admin("§4", "§e", "Admin", true, true, true, true),
|
||||||
Developer("§3", "§f", true, true, true),
|
Developer("§3", "§f", "Dev", true, true, true, true),
|
||||||
Moderator("§c", "§f", true, true, true),
|
Moderator("§c", "§f", "Mod", true, true, true, true),
|
||||||
Supporter("§9", "§f", false, true, true),
|
Supporter("§9", "§f", "Sup", false, true, true, true),
|
||||||
Builder("§2", "§f", false, true, false),
|
Builder("§2", "§f", "Arch", false, true, false, true),
|
||||||
YouTuber("§5", "§f", false, false, false),
|
YouTuber("§5", "§f", "YT", false, false, false, true),
|
||||||
Member("§7", "§7", false, false, false);
|
Member("§7", "§7", "", false, false, false, false);
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final String colorCode;
|
private final String colorCode;
|
||||||
@Getter
|
@Getter
|
||||||
private final String chatColorCode;
|
private final String chatColorCode;
|
||||||
@Getter
|
@Getter
|
||||||
private final boolean adminGroup;
|
private final String chatPrefix;
|
||||||
@Getter
|
@Getter
|
||||||
private final boolean teamGroup;
|
private final boolean adminGroup;
|
||||||
@Getter
|
@Getter
|
||||||
private final boolean checkSchematics;
|
private final boolean teamGroup;
|
||||||
|
@Getter
|
||||||
|
private final boolean checkSchematics;
|
||||||
|
@Getter
|
||||||
|
private final boolean privilegedMods;
|
||||||
|
|
||||||
|
public static UserGroup getUsergroup(String name) {
|
||||||
|
for(UserGroup group : values()) {
|
||||||
|
if(group.name().equalsIgnoreCase(name))
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException(name);
|
||||||
|
}
|
||||||
}
|
}
|
@ -41,6 +41,7 @@ public class Statement implements AutoCloseable {
|
|||||||
static final Consumer<Table<?>> schemaCreator;
|
static final Consumer<Table<?>> schemaCreator;
|
||||||
static final String ON_DUPLICATE_KEY;
|
static final String ON_DUPLICATE_KEY;
|
||||||
static final UnaryOperator<String> upsertWrapper;
|
static final UnaryOperator<String> upsertWrapper;
|
||||||
|
public static final String NULL_SAFE_EQUALS;
|
||||||
|
|
||||||
private static final boolean MYSQL_MODE;
|
private static final boolean MYSQL_MODE;
|
||||||
private static final boolean PRODUCTION_DATABASE;
|
private static final boolean PRODUCTION_DATABASE;
|
||||||
@ -73,6 +74,7 @@ public class Statement implements AutoCloseable {
|
|||||||
schemaCreator = table -> {};
|
schemaCreator = table -> {};
|
||||||
ON_DUPLICATE_KEY = " ON DUPLICATE KEY UPDATE ";
|
ON_DUPLICATE_KEY = " ON DUPLICATE KEY UPDATE ";
|
||||||
upsertWrapper = f -> f + " = VALUES(" + f + ")";
|
upsertWrapper = f -> f + " = VALUES(" + f + ")";
|
||||||
|
NULL_SAFE_EQUALS = " <=> ";
|
||||||
} else {
|
} else {
|
||||||
Connection connection;
|
Connection connection;
|
||||||
|
|
||||||
@ -89,10 +91,11 @@ public class Statement implements AutoCloseable {
|
|||||||
schemaCreator = Table::ensureExistanceInSqlite;
|
schemaCreator = Table::ensureExistanceInSqlite;
|
||||||
ON_DUPLICATE_KEY = " ON CONFLICT DO UPDATE SET ";
|
ON_DUPLICATE_KEY = " ON CONFLICT DO UPDATE SET ";
|
||||||
upsertWrapper = f -> f + " = " + f;
|
upsertWrapper = f -> f + " = " + f;
|
||||||
|
NULL_SAFE_EQUALS = " IS ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int connectionBudget = MAX_CONNECTIONS;
|
private static volatile int connectionBudget = MAX_CONNECTIONS;
|
||||||
|
|
||||||
public static void closeAll() {
|
public static void closeAll() {
|
||||||
synchronized (connections) {
|
synchronized (connections) {
|
||||||
@ -231,7 +234,7 @@ public class Statement implements AutoCloseable {
|
|||||||
|
|
||||||
private static Connection aquireConnection() {
|
private static Connection aquireConnection() {
|
||||||
synchronized (connections) {
|
synchronized (connections) {
|
||||||
if(connections.isEmpty() && connectionBudget == 0)
|
while(connections.isEmpty() && connectionBudget <= 0)
|
||||||
waitOnConnections();
|
waitOnConnections();
|
||||||
|
|
||||||
if(!connections.isEmpty()) {
|
if(!connections.isEmpty()) {
|
||||||
|
@ -54,7 +54,21 @@ public class ArgumentCommand extends TestSWCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Register
|
@Register
|
||||||
public void argument(String sender, @Quotable String arg) {
|
public void argument(String sender, String arg) {
|
||||||
throw new ExecutionIdentifier("RunArgument with String");
|
throw new ExecutionIdentifier("RunArgument with String");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Register
|
||||||
|
public void minLengthArgument(String sender, @Length(min = 3) @StaticValue({"he", "hello"}) String arg) {
|
||||||
|
throw new ExecutionIdentifier("RunLengthArgument with String");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Register
|
||||||
|
public void minAndMaxLengthArgument(String sender, @Length(min = 3, max = 3) @StaticValue({"wo", "world"}) String arg) {
|
||||||
|
throw new ExecutionIdentifier("RunLengthArgument with String");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void arrayLengthArgument(String sender, @ArrayLength(max = 3) @StaticValue({"one", "two", "three"}) String... args) {
|
||||||
|
throw new ExecutionIdentifier("RunArrayLengthArgument with String");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,34 +94,11 @@ public class ArgumentCommandTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testString() {
|
|
||||||
ArgumentCommand cmd = new ArgumentCommand();
|
|
||||||
try {
|
|
||||||
cmd.execute("test", "", new String[]{"Hello World"});
|
|
||||||
assert false;
|
|
||||||
} catch (Exception e) {
|
|
||||||
assertCMDFramework(e, ExecutionIdentifier.class, "RunArgument with String");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
cmd.execute("test", "", new String[]{"\"Hello World\""});
|
|
||||||
assert false;
|
|
||||||
} catch (Exception e) {
|
|
||||||
assertCMDFramework(e, ExecutionIdentifier.class, "RunArgument with String");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
cmd.execute("test", "", new String[]{"\"Hello", "World\""});
|
|
||||||
assert false;
|
|
||||||
} catch (Exception e) {
|
|
||||||
assertCMDFramework(e, ExecutionIdentifier.class, "RunArgument with String");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTabComplete() {
|
public void testTabComplete() {
|
||||||
ArgumentCommand cmd = new ArgumentCommand();
|
ArgumentCommand cmd = new ArgumentCommand();
|
||||||
List<String> strings = cmd.tabComplete("test", "", new String[]{""});
|
List<String> strings = cmd.tabComplete("test", "", new String[]{""});
|
||||||
assertTabCompletes(strings, "true", "false");
|
assertTabCompletes(strings, "true", "false", "hello", "wor");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -129,5 +106,23 @@ public class ArgumentCommandTest {
|
|||||||
ArgumentCommand cmd = new ArgumentCommand();
|
ArgumentCommand cmd = new ArgumentCommand();
|
||||||
List<String> strings = cmd.tabComplete("test", "", new String[]{"t"});
|
List<String> strings = cmd.tabComplete("test", "", new String[]{"t"});
|
||||||
assertTabCompletes(strings, "true", "t");
|
assertTabCompletes(strings, "true", "t");
|
||||||
|
|
||||||
|
strings = cmd.tabComplete("test", "", new String[]{"h"});
|
||||||
|
assertTabCompletes(strings, "h", "hello");
|
||||||
|
|
||||||
|
strings = cmd.tabComplete("test", "", new String[]{"hel"});
|
||||||
|
assertTabCompletes(strings, "hel", "hello");
|
||||||
|
|
||||||
|
strings = cmd.tabComplete("test", "", new String[]{"w"});
|
||||||
|
assertTabCompletes(strings, "w", "wor");
|
||||||
|
|
||||||
|
strings = cmd.tabComplete("test", "", new String[]{"wor"});
|
||||||
|
assertTabCompletes(strings, "wor");
|
||||||
|
|
||||||
|
strings = cmd.tabComplete("test", "", new String[]{"worl"});
|
||||||
|
assertTabCompletes(strings, "wor", "worl");
|
||||||
|
|
||||||
|
strings = cmd.tabComplete("test", "", new String[]{"one", "two", "three", "one"});
|
||||||
|
assertTabCompletes(strings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,17 +39,18 @@ public class BetterExceptionCommand extends TestSWCommand {
|
|||||||
public TestTypeMapper<String> tabCompleteException() {
|
public TestTypeMapper<String> tabCompleteException() {
|
||||||
return new TestTypeMapper<String>() {
|
return new TestTypeMapper<String>() {
|
||||||
@Override
|
@Override
|
||||||
public String map(String sender, String[] previousArguments, String s) {
|
public String map(String sender, PreviousArguments previousArguments, String s) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean validate(String sender, String value, MessageSender messageSender) {
|
public boolean validate(String sender, String value, MessageSender messageSender) {
|
||||||
|
System.out.println("Validate: " + value);
|
||||||
throw new SecurityException();
|
throw new SecurityException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<String> tabCompletes(String sender, String[] previousArguments, String s) {
|
public Collection<String> tabCompletes(String sender, PreviousArguments previousArguments, String s) {
|
||||||
throw new SecurityException();
|
throw new SecurityException();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -41,15 +41,14 @@ public class CacheCommand extends TestSWCommand {
|
|||||||
@Cached
|
@Cached
|
||||||
@Mapper(value = "int", local = true)
|
@Mapper(value = "int", local = true)
|
||||||
public AbstractTypeMapper<String, Integer> typeMapper() {
|
public AbstractTypeMapper<String, Integer> typeMapper() {
|
||||||
System.out.println("TypeMapper register");
|
|
||||||
return new TestTypeMapper<Integer>() {
|
return new TestTypeMapper<Integer>() {
|
||||||
@Override
|
@Override
|
||||||
public Integer map(String sender, String[] previousArguments, String s) {
|
public Integer map(String sender, PreviousArguments previousArguments, String s) {
|
||||||
return Integer.parseInt(s);
|
return Integer.parseInt(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<String> tabCompletes(String sender, String[] previousArguments, String s) {
|
public Collection<String> tabCompletes(String sender, PreviousArguments previousArguments, String s) {
|
||||||
return Arrays.asList(count.getAndIncrement() + "");
|
return Arrays.asList(count.getAndIncrement() + "");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -36,6 +36,14 @@ public class CacheCommandTest {
|
|||||||
assertThat(tabCompletions1, is(equalTo(tabCompletions2)));
|
assertThat(tabCompletions1, is(equalTo(tabCompletions2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCachingWithDifferentMessages() {
|
||||||
|
CacheCommand cmd = new CacheCommand();
|
||||||
|
List<String> tabCompletions1 = cmd.tabComplete("test", "", new String[]{""});
|
||||||
|
List<String> tabCompletions2 = cmd.tabComplete("test", "", new String[]{"0"});
|
||||||
|
assertThat(tabCompletions1, is(equalTo(tabCompletions2)));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCachingWithDifferentSenders() {
|
public void testCachingWithDifferentSenders() {
|
||||||
CacheCommand cmd = new CacheCommand();
|
CacheCommand cmd = new CacheCommand();
|
||||||
|
@ -43,7 +43,7 @@ public class NullMapperCommand extends TestSWCommand {
|
|||||||
public TestTypeMapper<String> typeMapper() {
|
public TestTypeMapper<String> typeMapper() {
|
||||||
return new TestTypeMapper<String>() {
|
return new TestTypeMapper<String>() {
|
||||||
@Override
|
@Override
|
||||||
public String map(String sender, String[] previousArguments, String s) {
|
public String map(String sender, PreviousArguments previousArguments, String s) {
|
||||||
if (s.equals("Hello World")) {
|
if (s.equals("Hello World")) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -51,7 +51,7 @@ public class NullMapperCommand extends TestSWCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<String> tabCompletes(String sender, String[] previousArguments, String s) {
|
public Collection<String> tabCompletes(String sender, PreviousArguments previousArguments, String s) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2020 SteamWar.de-Serverteam
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@ -19,7 +19,17 @@
|
|||||||
|
|
||||||
package de.steamwar.command;
|
package de.steamwar.command;
|
||||||
|
|
||||||
class CommandNoHelpException extends RuntimeException {
|
import de.steamwar.command.dto.ExecutionIdentifier;
|
||||||
|
import de.steamwar.command.dto.TestSWCommand;
|
||||||
|
|
||||||
CommandNoHelpException() {}
|
public class NumberValidatorCommand extends TestSWCommand {
|
||||||
|
|
||||||
|
public NumberValidatorCommand() {
|
||||||
|
super("numberValidator");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Register
|
||||||
|
public void test(String sender, @Min(intValue = 0) @Max(intValue = 10) int i) {
|
||||||
|
throw new ExecutionIdentifier("RunNumberValidator with int");
|
||||||
|
}
|
||||||
}
|
}
|
51
testsrc/de/steamwar/command/NumberValidatorCommandTest.java
Normale Datei
51
testsrc/de/steamwar/command/NumberValidatorCommandTest.java
Normale Datei
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.command;
|
||||||
|
|
||||||
|
import de.steamwar.command.dto.ExecutionIdentifier;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static de.steamwar.AssertionUtils.assertCMDFramework;
|
||||||
|
|
||||||
|
public class NumberValidatorCommandTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMinValue() {
|
||||||
|
NumberValidatorCommand command = new NumberValidatorCommand();
|
||||||
|
command.execute("sender", "", new String[]{"-1"});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMaxValue() {
|
||||||
|
NumberValidatorCommand command = new NumberValidatorCommand();
|
||||||
|
command.execute("sender", "", new String[]{"11"});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidValue() {
|
||||||
|
try {
|
||||||
|
NumberValidatorCommand command = new NumberValidatorCommand();
|
||||||
|
command.execute("sender", "", new String[]{"2"});
|
||||||
|
assert false;
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertCMDFramework(e, ExecutionIdentifier.class, "RunNumberValidator with int");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
70
testsrc/de/steamwar/command/PartOfCommand.java
Normale Datei
70
testsrc/de/steamwar/command/PartOfCommand.java
Normale Datei
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.command;
|
||||||
|
|
||||||
|
import de.steamwar.command.dto.ExecutionIdentifier;
|
||||||
|
import de.steamwar.command.dto.TestSWCommand;
|
||||||
|
import de.steamwar.command.dto.TestTypeMapper;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
public class PartOfCommand {
|
||||||
|
|
||||||
|
public static class ParentCommand extends TestSWCommand {
|
||||||
|
|
||||||
|
public ParentCommand() {
|
||||||
|
super("parent");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Register
|
||||||
|
public void execute(String s, String... args) {
|
||||||
|
throw new ExecutionIdentifier("ParentCommand with String...");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Mapper("test")
|
||||||
|
public TestTypeMapper<Integer> typeMapper() {
|
||||||
|
return new TestTypeMapper<Integer>() {
|
||||||
|
@Override
|
||||||
|
public Integer map(String sender, PreviousArguments previousArguments, String s) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<String> tabCompletes(String sender, PreviousArguments previousArguments, String s) {
|
||||||
|
return Arrays.asList(s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AbstractSWCommand.PartOf(ParentCommand.class)
|
||||||
|
public static class SubCommand extends TestSWCommand {
|
||||||
|
|
||||||
|
public SubCommand() {
|
||||||
|
super(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Register
|
||||||
|
public void execute(String s, @Mapper("test") int i) {
|
||||||
|
throw new ExecutionIdentifier("SubCommand with int " + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
42
testsrc/de/steamwar/command/PartOfCommandTest.java
Normale Datei
42
testsrc/de/steamwar/command/PartOfCommandTest.java
Normale Datei
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.command;
|
||||||
|
|
||||||
|
import de.steamwar.command.dto.ExecutionIdentifier;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static de.steamwar.AssertionUtils.assertCMDFramework;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
|
||||||
|
public class PartOfCommandTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMerging() {
|
||||||
|
PartOfCommand.ParentCommand command = new PartOfCommand.ParentCommand();
|
||||||
|
new PartOfCommand.SubCommand();
|
||||||
|
try {
|
||||||
|
command.execute("test", "", new String[]{"0"});
|
||||||
|
assertThat(true, is(false));
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertCMDFramework(e, ExecutionIdentifier.class, "SubCommand with int -1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
testsrc/de/steamwar/command/PreviousArgumentCommand.java
Normale Datei
54
testsrc/de/steamwar/command/PreviousArgumentCommand.java
Normale Datei
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.command;
|
||||||
|
|
||||||
|
import de.steamwar.command.dto.ExecutionIdentifier;
|
||||||
|
import de.steamwar.command.dto.TestSWCommand;
|
||||||
|
import de.steamwar.command.dto.TestTypeMapper;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
public class PreviousArgumentCommand extends TestSWCommand {
|
||||||
|
|
||||||
|
public PreviousArgumentCommand() {
|
||||||
|
super("previous");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Register
|
||||||
|
public void genericCommand(String s, int i, String l) {
|
||||||
|
throw new ExecutionIdentifier(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ClassMapper(value = String.class, local = true)
|
||||||
|
public TestTypeMapper<String> typeMapper() {
|
||||||
|
return new TestTypeMapper<String>() {
|
||||||
|
@Override
|
||||||
|
public String map(String sender, PreviousArguments previousArguments, String s) {
|
||||||
|
return "RunTypeMapper_" + previousArguments.getMappedArg(0) + "_" + previousArguments.getMappedArg(0).getClass().getSimpleName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<String> tabCompletes(String sender, PreviousArguments previousArguments, String s) {
|
||||||
|
return Arrays.asList(previousArguments.getMappedArg(0) + "");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
56
testsrc/de/steamwar/command/PreviousArgumentCommandTest.java
Normale Datei
56
testsrc/de/steamwar/command/PreviousArgumentCommandTest.java
Normale Datei
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.command;
|
||||||
|
|
||||||
|
import de.steamwar.command.dto.ExecutionIdentifier;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static de.steamwar.AssertionUtils.assertCMDFramework;
|
||||||
|
import static de.steamwar.AssertionUtils.assertTabCompletes;
|
||||||
|
|
||||||
|
public class PreviousArgumentCommandTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPrevArg1() {
|
||||||
|
PreviousArgumentCommand command = new PreviousArgumentCommand();
|
||||||
|
List<String> strings = command.tabComplete("", "", new String[]{"1", ""});
|
||||||
|
assertTabCompletes(strings, "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPrevArg2() {
|
||||||
|
PreviousArgumentCommand command = new PreviousArgumentCommand();
|
||||||
|
List<String> strings = command.tabComplete("", "", new String[]{"2", ""});
|
||||||
|
assertTabCompletes(strings, "2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPrevArgExecute() {
|
||||||
|
PreviousArgumentCommand command = new PreviousArgumentCommand();
|
||||||
|
try {
|
||||||
|
command.execute("", "", new String[]{"2", "2"});
|
||||||
|
assert false;
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertCMDFramework(e, ExecutionIdentifier.class, "RunTypeMapper_2_Integer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
package de.steamwar.command;
|
package de.steamwar.command;
|
||||||
|
|
||||||
import de.steamwar.command.AbstractSWCommand.Register;
|
|
||||||
import de.steamwar.command.dto.ExecutionIdentifier;
|
import de.steamwar.command.dto.ExecutionIdentifier;
|
||||||
import de.steamwar.command.dto.TestSWCommand;
|
import de.steamwar.command.dto.TestSWCommand;
|
||||||
|
|
||||||
@ -29,7 +28,7 @@ public class SimpleCommand extends TestSWCommand {
|
|||||||
super("simple");
|
super("simple");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Register(value = "a", help = true)
|
@Register(value = "a", noTabComplete = true)
|
||||||
public void test(String s, String... varargs) {
|
public void test(String s, String... varargs) {
|
||||||
throw new ExecutionIdentifier("RunSimple with Varargs");
|
throw new ExecutionIdentifier("RunSimple with Varargs");
|
||||||
}
|
}
|
||||||
|
@ -41,11 +41,13 @@ public class StaticValueCommandTest {
|
|||||||
StaticValueCommand cmd = new StaticValueCommand();
|
StaticValueCommand cmd = new StaticValueCommand();
|
||||||
try {
|
try {
|
||||||
cmd.execute("", "", new String[] {"hello"});
|
cmd.execute("", "", new String[] {"hello"});
|
||||||
|
assert false;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with hello");
|
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with hello");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
cmd.execute("", "", new String[] {"world"});
|
cmd.execute("", "", new String[] {"world"});
|
||||||
|
assert false;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with world");
|
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with world");
|
||||||
}
|
}
|
||||||
@ -56,16 +58,19 @@ public class StaticValueCommandTest {
|
|||||||
StaticValueCommand cmd = new StaticValueCommand();
|
StaticValueCommand cmd = new StaticValueCommand();
|
||||||
try {
|
try {
|
||||||
cmd.execute("", "", new String[] {"-a"});
|
cmd.execute("", "", new String[] {"-a"});
|
||||||
|
assert false;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with false");
|
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with false");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
cmd.execute("", "", new String[] {"-b"});
|
cmd.execute("", "", new String[] {"-b"});
|
||||||
|
assert false;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with true");
|
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with true");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
cmd.execute("", "", new String[] {"-c"});
|
cmd.execute("", "", new String[] {"-c"});
|
||||||
|
assert false;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with true");
|
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with true");
|
||||||
}
|
}
|
||||||
@ -76,16 +81,19 @@ public class StaticValueCommandTest {
|
|||||||
StaticValueCommand cmd = new StaticValueCommand();
|
StaticValueCommand cmd = new StaticValueCommand();
|
||||||
try {
|
try {
|
||||||
cmd.execute("", "", new String[] {"-d"});
|
cmd.execute("", "", new String[] {"-d"});
|
||||||
|
assert false;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with true");
|
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with true");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
cmd.execute("", "", new String[] {"-e"});
|
cmd.execute("", "", new String[] {"-e"});
|
||||||
|
assert false;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with false");
|
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with false");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
cmd.execute("", "", new String[] {"-f"});
|
cmd.execute("", "", new String[] {"-f"});
|
||||||
|
assert false;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with true");
|
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with true");
|
||||||
}
|
}
|
||||||
@ -96,16 +104,19 @@ public class StaticValueCommandTest {
|
|||||||
StaticValueCommand cmd = new StaticValueCommand();
|
StaticValueCommand cmd = new StaticValueCommand();
|
||||||
try {
|
try {
|
||||||
cmd.execute("", "", new String[] {"-g"});
|
cmd.execute("", "", new String[] {"-g"});
|
||||||
|
assert false;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with int 0");
|
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with int 0");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
cmd.execute("", "", new String[] {"-h"});
|
cmd.execute("", "", new String[] {"-h"});
|
||||||
|
assert false;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with int 1");
|
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with int 1");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
cmd.execute("", "", new String[] {"-i"});
|
cmd.execute("", "", new String[] {"-i"});
|
||||||
|
assert false;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with int 2");
|
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with int 2");
|
||||||
}
|
}
|
||||||
@ -116,16 +127,19 @@ public class StaticValueCommandTest {
|
|||||||
StaticValueCommand cmd = new StaticValueCommand();
|
StaticValueCommand cmd = new StaticValueCommand();
|
||||||
try {
|
try {
|
||||||
cmd.execute("", "", new String[] {"-j"});
|
cmd.execute("", "", new String[] {"-j"});
|
||||||
|
assert false;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with long 0");
|
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with long 0");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
cmd.execute("", "", new String[] {"-k"});
|
cmd.execute("", "", new String[] {"-k"});
|
||||||
|
assert false;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with long 1");
|
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with long 1");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
cmd.execute("", "", new String[] {"-l"});
|
cmd.execute("", "", new String[] {"-l"});
|
||||||
|
assert false;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with long 2");
|
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with long 2");
|
||||||
}
|
}
|
||||||
|
58
testsrc/de/steamwar/command/SubCMDSortingCommand.java
Normale Datei
58
testsrc/de/steamwar/command/SubCMDSortingCommand.java
Normale Datei
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.command;
|
||||||
|
|
||||||
|
import de.steamwar.command.dto.ExecutionIdentifier;
|
||||||
|
import de.steamwar.command.dto.TestSWCommand;
|
||||||
|
import de.steamwar.command.dto.TestTypeMapper;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
public class SubCMDSortingCommand extends TestSWCommand {
|
||||||
|
|
||||||
|
public SubCMDSortingCommand() {
|
||||||
|
super("subcmdsorting");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Register
|
||||||
|
public void test(String s) {
|
||||||
|
throw new ExecutionIdentifier("Command with 0 parameters");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Register
|
||||||
|
public void test(String s, String args) {
|
||||||
|
throw new ExecutionIdentifier("Command with 1 parameter");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Register
|
||||||
|
public void test(String s, String i1, String i2, String i3, String... args) {
|
||||||
|
throw new ExecutionIdentifier("Command with 3+n parameters");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Register
|
||||||
|
public void test(String s, String... args) {
|
||||||
|
throw new ExecutionIdentifier("Command with n parameters");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ClassMapper(value = String.class, local = true)
|
||||||
|
public AbstractTypeMapper<String, String> stringMapper() {
|
||||||
|
return SWCommandUtils.createMapper(s -> s, Collections::singletonList);
|
||||||
|
}
|
||||||
|
}
|
83
testsrc/de/steamwar/command/SubCMDSortingCommandTest.java
Normale Datei
83
testsrc/de/steamwar/command/SubCMDSortingCommandTest.java
Normale Datei
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.command;
|
||||||
|
|
||||||
|
import de.steamwar.command.dto.ExecutionIdentifier;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static de.steamwar.AssertionUtils.assertCMDFramework;
|
||||||
|
|
||||||
|
public class SubCMDSortingCommandTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoArgs() {
|
||||||
|
SubCMDSortingCommand cmd = new SubCMDSortingCommand();
|
||||||
|
try {
|
||||||
|
cmd.execute("", "", new String[]{});
|
||||||
|
assert false;
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertCMDFramework(e, ExecutionIdentifier.class, "Command with 0 parameters");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOneArgs() {
|
||||||
|
SubCMDSortingCommand cmd = new SubCMDSortingCommand();
|
||||||
|
try {
|
||||||
|
cmd.execute("", "", new String[]{"Hello"});
|
||||||
|
assert false;
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertCMDFramework(e, ExecutionIdentifier.class, "Command with 1 parameter");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOneArgsVarArg() {
|
||||||
|
SubCMDSortingCommand cmd = new SubCMDSortingCommand();
|
||||||
|
try {
|
||||||
|
cmd.execute("", "", new String[]{"Hello", "World"});
|
||||||
|
assert false;
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertCMDFramework(e, ExecutionIdentifier.class, "Command with n parameters");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testThreeArgsVarArg() {
|
||||||
|
SubCMDSortingCommand cmd = new SubCMDSortingCommand();
|
||||||
|
try {
|
||||||
|
cmd.execute("", "", new String[]{"Hello", "World", "YoyoNow", "Hugo"});
|
||||||
|
assert false;
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertCMDFramework(e, ExecutionIdentifier.class, "Command with 3+n parameters");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testThreeArgsVarArg2() {
|
||||||
|
SubCMDSortingCommand cmd = new SubCMDSortingCommand();
|
||||||
|
try {
|
||||||
|
cmd.execute("", "", new String[]{"Hello", "World", "YoyoNow"});
|
||||||
|
assert false;
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertCMDFramework(e, ExecutionIdentifier.class, "Command with 3+n parameters");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -60,4 +60,26 @@ public class ValidatorCommandTest {
|
|||||||
assertCMDFramework(e, ExecutionIdentifier.class, "RunOnErrorDouble");
|
assertCMDFramework(e, ExecutionIdentifier.class, "RunOnErrorDouble");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvert() {
|
||||||
|
ValidatorInvertCommand cmd = new ValidatorInvertCommand();
|
||||||
|
try {
|
||||||
|
cmd.execute("test", "", new String[]{"false", "true"});
|
||||||
|
assertThat(true, is(false));
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertCMDFramework(e, ExecutionIdentifier.class, "RunTestInvert");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvertOther() {
|
||||||
|
ValidatorInvertCommand cmd = new ValidatorInvertCommand();
|
||||||
|
try {
|
||||||
|
cmd.execute("test", "", new String[]{"Hello", "0"});
|
||||||
|
assertThat(true, is(false));
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertCMDFramework(e, ExecutionIdentifier.class, "RunTestInvert2");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
51
testsrc/de/steamwar/command/ValidatorInvertCommand.java
Normale Datei
51
testsrc/de/steamwar/command/ValidatorInvertCommand.java
Normale Datei
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.command;
|
||||||
|
|
||||||
|
import de.steamwar.command.dto.ExecutionIdentifier;
|
||||||
|
import de.steamwar.command.dto.TestSWCommand;
|
||||||
|
import de.steamwar.command.dto.TestValidator;
|
||||||
|
|
||||||
|
public class ValidatorInvertCommand extends TestSWCommand {
|
||||||
|
|
||||||
|
public ValidatorInvertCommand() {
|
||||||
|
super("testvalidator");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Register
|
||||||
|
public void test(@Validator(value = "Text", invert = true) String sender, boolean b, boolean b2) {
|
||||||
|
System.out.println("test: " + sender + " " + b + " " + b2);
|
||||||
|
throw new ExecutionIdentifier("RunTestInvert");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Register
|
||||||
|
public void test(String sender, @Validator(value = "Text", invert = true) String h, int i) {
|
||||||
|
System.out.println("test: " + sender + " " + h + " " + i);
|
||||||
|
throw new ExecutionIdentifier("RunTestInvert2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Validator(value = "Text", local = true)
|
||||||
|
public TestValidator<String> testValidator() {
|
||||||
|
return (sender, value, messageSender) -> {
|
||||||
|
System.out.println("testValidator: " + sender + " " + value + " " + messageSender);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -51,9 +51,11 @@ public class TestSWCommand extends AbstractSWCommand<String> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void commandSystemError(String sender, CommandFrameworkException e) {
|
protected void commandSystemError(String sender, CommandFrameworkException e) {
|
||||||
|
System.out.println("CommandSystemError: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void commandSystemWarning(Supplier<String> message) {
|
protected void commandSystemWarning(Supplier<String> message) {
|
||||||
|
System.out.println("CommandSystemWarning: " + message.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren