Dieser Commit ist enthalten in:
Ursprung
4e46e05a3b
Commit
cfd9b4107c
@ -23,6 +23,7 @@ import java.lang.annotation.*;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.IntPredicate;
|
||||
import java.util.function.Supplier;
|
||||
@ -108,7 +109,9 @@ public abstract class AbstractSWCommand<T> {
|
||||
private synchronized void createMapping() {
|
||||
List<Method> methods = methods();
|
||||
for (Method method : methods) {
|
||||
Cached cached = method.getAnnotation(Cached.class);
|
||||
addMapper(Mapper.class, method, i -> i == 0, false, AbstractTypeMapper.class, (anno, typeMapper) -> {
|
||||
addToCache(cached, typeMapper);
|
||||
if (anno.local()) {
|
||||
localTypeMapper.putIfAbsent(anno.value(), (AbstractTypeMapper<T, ?>) typeMapper);
|
||||
} else {
|
||||
@ -116,6 +119,7 @@ public abstract class AbstractSWCommand<T> {
|
||||
}
|
||||
});
|
||||
addMapper(ClassMapper.class, method, i -> i == 0, false, AbstractTypeMapper.class, (anno, typeMapper) -> {
|
||||
addToCache(cached, typeMapper);
|
||||
if (anno.local()) {
|
||||
localTypeMapper.putIfAbsent(anno.value().getTypeName(), (AbstractTypeMapper<T, ?>) typeMapper);
|
||||
} else {
|
||||
@ -209,6 +213,14 @@ public abstract class AbstractSWCommand<T> {
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
private void addToCache(Cached cached, AbstractTypeMapper<?, ?> typeMapper) {
|
||||
if (cached != null) {
|
||||
TabCompletionCache.cached.add(typeMapper);
|
||||
if (cached.global()) TabCompletionCache.global.add(typeMapper);
|
||||
TabCompletionCache.cacheDuration.put(typeMapper, cached.timeUnit().toMillis(cached.cacheDuration()));
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends Annotation> void add(Class<T> annotation, Method method, IntPredicate parameterTester, boolean firstParameter, Class<?> returnType, BiConsumer<T, Parameter[]> consumer) {
|
||||
T[] anno = SWCommandUtils.getAnnotation(method, annotation);
|
||||
if (anno == null || anno.length == 0) return;
|
||||
@ -315,6 +327,14 @@ public abstract class AbstractSWCommand<T> {
|
||||
boolean local() default false;
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.METHOD})
|
||||
protected @interface Cached {
|
||||
long cacheDuration() default 5;
|
||||
TimeUnit timeUnit() default TimeUnit.SECONDS;
|
||||
boolean global() default false;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.PARAMETER, ElementType.METHOD})
|
||||
|
@ -169,7 +169,7 @@ class CommandPart<T> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Collection<String> strings = typeMapper.tabCompletes(sender, Arrays.copyOf(args, args.length - 1), args[args.length - 1]);
|
||||
Collection<String> strings = tabCompletes(sender, args, args.length - 1);
|
||||
if (strings != null) {
|
||||
current.addAll(strings);
|
||||
}
|
||||
@ -197,6 +197,12 @@ class CommandPart<T> {
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<String> tabCompletes(T sender, String[] args, int startIndex) {
|
||||
return TabCompletionCache.tabComplete(sender, typeMapper, command, () -> {
|
||||
return typeMapper.tabCompletes(sender, Arrays.copyOf(args, startIndex), args[startIndex]);
|
||||
});
|
||||
}
|
||||
|
||||
private CheckArgumentResult checkArgument(Consumer<Runnable> errors, GuardCheckType guardCheckType, T sender, String[] args, int index) {
|
||||
try {
|
||||
Object value = typeMapper.map(sender, Arrays.copyOf(args, index), args[index]);
|
||||
|
57
src/de/steamwar/command/TabCompletionCache.java
Normale Datei
57
src/de/steamwar/command/TabCompletionCache.java
Normale Datei
@ -0,0 +1,57 @@
|
||||
package de.steamwar.command;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@UtilityClass
|
||||
public class TabCompletionCache {
|
||||
|
||||
private Map<Key, TabCompletions> tabCompletionCache = new HashMap<>();
|
||||
Set<AbstractTypeMapper<?, ?>> cached = new HashSet<>();
|
||||
Set<AbstractTypeMapper<?, ?>> global = new HashSet<>();
|
||||
Map<AbstractTypeMapper<?, ?>, Long> cacheDuration = new HashMap<>();
|
||||
|
||||
@EqualsAndHashCode
|
||||
@AllArgsConstructor
|
||||
private static class Key {
|
||||
private Object sender;
|
||||
private AbstractTypeMapper<?, ?> typeMapper;
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
private static class TabCompletions {
|
||||
private AbstractSWCommand<?> command;
|
||||
private long timestamp;
|
||||
private Collection<String> tabCompletions;
|
||||
}
|
||||
|
||||
Collection<String> tabComplete(Object sender, AbstractTypeMapper<?, ?> typeMapper, AbstractSWCommand<?> command, Supplier<Collection<String>> tabCompleteSupplier) {
|
||||
if (!cached.contains(typeMapper)) return tabCompleteSupplier.get();
|
||||
Key key = global.contains(typeMapper) ? new Key(null, typeMapper) : new Key(sender, typeMapper);
|
||||
TabCompletions tabCompletions = tabCompletionCache.computeIfAbsent(key, ignore -> {
|
||||
return new TabCompletions(command, System.currentTimeMillis(), tabCompleteSupplier.get());
|
||||
});
|
||||
if (tabCompletions.command != command) {
|
||||
tabCompletions = new TabCompletions(command, System.currentTimeMillis(), tabCompleteSupplier.get());
|
||||
tabCompletionCache.put(key, tabCompletions);
|
||||
}
|
||||
tabCompletions.timestamp = System.currentTimeMillis();
|
||||
return tabCompletions.tabCompletions;
|
||||
}
|
||||
|
||||
public void invalidateOldEntries() {
|
||||
Set<Key> toRemove = new HashSet<>();
|
||||
for (Map.Entry<Key, TabCompletions> tabCompletionsEntry : tabCompletionCache.entrySet()) {
|
||||
if (System.currentTimeMillis() - tabCompletionsEntry.getValue().timestamp > cacheDuration.get(tabCompletionsEntry.getKey().typeMapper)) {
|
||||
toRemove.add(tabCompletionsEntry.getKey());
|
||||
}
|
||||
}
|
||||
for (Key key : toRemove) {
|
||||
tabCompletionCache.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren