Implemented new dynamic registry system

This commit is contained in:
Rezel 2020-07-03 15:21:50 -06:00
parent 851b0688c1
commit 3a0af57124
22 changed files with 280 additions and 16 deletions

View File

@ -33,6 +33,8 @@ dependencies {
compile group: 'com.google.code.gson', name: 'gson', version:'2.8.2'
includeLibs group: 'com.google.inject', name: 'guice', version:'4.0'
compile group: 'com.google.inject', name: 'guice', version:'4.0'
compile group: 'com.google.guava', name: 'guava', version: '29.0-jre'
// For spigot api
implementation "org.spigotmc:spigot-api:1.16.1-R0.1-SNAPSHOT"

View File

@ -5,17 +5,19 @@ import com.google.inject.Injector;
import com.sekwah.advancedportals.core.api.commands.SubCommand;
import com.sekwah.advancedportals.core.api.destination.Destination;
import com.sekwah.advancedportals.core.api.portal.AdvancedPortal;
import com.sekwah.advancedportals.core.api.registry.TagRegistry;
import com.sekwah.advancedportals.core.api.registry.WarpEffectRegistry;
import com.sekwah.advancedportals.core.api.services.DestinationServices;
import com.sekwah.advancedportals.core.api.services.PortalServices;
import com.sekwah.advancedportals.core.api.services.PortalTempDataServices;
import com.sekwah.advancedportals.core.registry.TagRegistry;
import com.sekwah.advancedportals.core.registry.WarpEffectRegistry;
import com.sekwah.advancedportals.core.services.DestinationServices;
import com.sekwah.advancedportals.core.services.PortalServices;
import com.sekwah.advancedportals.core.services.PortalTempDataServices;
import com.sekwah.advancedportals.core.commands.CommandWithSubCommands;
import com.sekwah.advancedportals.core.commands.subcommands.desti.CreateDestiSubCommand;
import com.sekwah.advancedportals.core.commands.subcommands.portal.*;
import com.sekwah.advancedportals.core.config.RepositoryModule;
import com.sekwah.advancedportals.core.data.DataStorage;
import com.sekwah.advancedportals.ConfigRepository;
import com.sekwah.advancedportals.core.registry.RegisterBuilder;
import com.sekwah.advancedportals.core.registry.Registrar;
import com.sekwah.advancedportals.core.util.InfoLogger;
import com.sekwah.advancedportals.core.util.Lang;
import com.sekwah.advancedportals.core.connector.command.CommandRegister;
@ -69,6 +71,12 @@ public class AdvancedPortalsCore {
this.onEnable();
}
public void test() {
Registrar registrar = RegisterBuilder.newBuilder()
.inheritPermissions(true)
.build();
}
private int checkMcVer(int[] mcVer) {
int maxSupportedVer = 13;
int minSupportedVer = 13;

View File

@ -1,8 +1,8 @@
package com.sekwah.advancedportals.core;
import com.google.inject.Inject;
import com.sekwah.advancedportals.core.api.services.PortalServices;
import com.sekwah.advancedportals.core.api.services.PortalTempDataServices;
import com.sekwah.advancedportals.core.services.PortalServices;
import com.sekwah.advancedportals.core.services.PortalTempDataServices;
import com.sekwah.advancedportals.core.data.PlayerLocation;
import com.sekwah.advancedportals.core.data.PortalLocation;
import com.sekwah.advancedportals.core.util.Lang;

View File

@ -2,7 +2,7 @@ package com.sekwah.advancedportals.core.api.destination;
import com.google.gson.annotations.SerializedName;
import com.sekwah.advancedportals.core.AdvancedPortalsCore;
import com.sekwah.advancedportals.core.api.registry.TagRegistry;
import com.sekwah.advancedportals.core.registry.TagRegistry;
import com.sekwah.advancedportals.core.api.warphandler.ActivationData;
import com.sekwah.advancedportals.core.api.warphandler.TagHandler;
import com.sekwah.advancedportals.core.data.DataTag;

View File

@ -2,7 +2,7 @@ package com.sekwah.advancedportals.core.api.portal;
import com.google.gson.annotations.SerializedName;
import com.sekwah.advancedportals.core.AdvancedPortalsCore;
import com.sekwah.advancedportals.core.api.registry.TagRegistry;
import com.sekwah.advancedportals.core.registry.TagRegistry;
import com.sekwah.advancedportals.core.api.warphandler.ActivationData;
import com.sekwah.advancedportals.core.api.warphandler.TagHandler;
import com.sekwah.advancedportals.core.data.DataTag;

View File

@ -1,7 +1,7 @@
package com.sekwah.advancedportals.core.commands;
import com.sekwah.advancedportals.core.api.commands.SubCommand;
import com.sekwah.advancedportals.core.api.registry.SubCommandRegistry;
import com.sekwah.advancedportals.core.registry.SubCommandRegistry;
import com.sekwah.advancedportals.core.util.Lang;
import com.sekwah.advancedportals.core.connector.container.CommandSenderContainer;

View File

@ -0,0 +1,16 @@
package com.sekwah.advancedportals.core.registry;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Cmd {
String name();
//TODO Convert to enum
String parentCommand() default "";
boolean isEnabled() default true;
int minArgs() default 0;
String description() default "";
String[] permissions() default {};
}

View File

@ -0,0 +1,18 @@
package com.sekwah.advancedportals.core.registry;
import com.google.common.collect.ImmutableList;
import com.sekwah.advancedportals.core.connector.container.CommandSenderContainer;
public class CommandDemo implements CommandHandler {
@Override
public void onExecute(String commandName, String parentCommand, CommandSenderContainer sender, ImmutableList<String> args) {
}
@Override
public void onCommandFailure(String[] command, CommandSenderContainer sender, CommandException exception) {
}
}

View File

@ -0,0 +1,6 @@
package com.sekwah.advancedportals.core.registry;
//TODO
public class CommandErrorException extends Exception {
private String reason;
}

View File

@ -0,0 +1,19 @@
package com.sekwah.advancedportals.core.registry;
public class CommandException {
private ErrorCode errorCode;
private String message;
public CommandException(ErrorCode errorCode, String message) {
this.errorCode = errorCode;
this.message = message;
}
public ErrorCode getErrorCode() {
return errorCode;
}
public String getMessage() {
return message;
}
}

View File

@ -0,0 +1,12 @@
package com.sekwah.advancedportals.core.registry;
import com.google.common.collect.ImmutableList;
import com.sekwah.advancedportals.core.connector.container.CommandSenderContainer;
public interface CommandHandler {
void onExecute(String commandName, String parentCommand, CommandSenderContainer sender, ImmutableList<String> args);
default void onCommandFailure(String[] command, CommandSenderContainer sender, CommandException exception, ImmutableList<String> args) {
sender.sendMessage(exception.getMessage());
}
}

View File

@ -0,0 +1,12 @@
package com.sekwah.advancedportals.core.registry;
public enum ErrorCode {
INSUFFICIENT_ARGUMENTS(""),
NO_PERMISSION("");
;
ErrorCode(String message) {
}
}

View File

@ -0,0 +1,90 @@
package com.sekwah.advancedportals.core.registry;
import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.ClassPath;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class RegisterBuilder<T extends CommandHandler> {
public static RegisterBuilder newBuilder() {
return new RegisterBuilder();
}
private RegisterBuilder() {
}
private boolean allowPermissionInheritance;
private String scanDirectory;
private final Class<T> genericType = (Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
public RegisterBuilder<T> inheritPermissions(boolean allowInheritance) {
allowPermissionInheritance = allowInheritance;
return this;
}
public RegisterBuilder<T> scanDirectory(String directoryName) {
this.scanDirectory = directoryName;
return this;
}
//TODO I don't know if we want to use this as it is marked as Unstable.
public Registrar<T> build() {
// Table<String, String, T> commandMap = HashBasedTable.create();
Map<Cmd, T> commandMap = new HashMap<>();
ImmutableSet<ClassPath.ClassInfo> classInfo;
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
ClassPath classPath = null;
try {
classPath = ClassPath.from(loader);
} catch (IOException e) {
e.printStackTrace();
}
if (null == scanDirectory || scanDirectory.isEmpty()) {
classInfo = classPath.getTopLevelClasses(scanDirectory);
} else {
classInfo = classPath.getTopLevelClasses();
}
//TODO implement blackout of already registered commands.
//TODO If there are duplicates ignore them and throw a warning in console.
Map<Cmd, Class<?>> commandClasses = classInfo.stream().map(ClassPath.ClassInfo::load)
.filter(t -> t.isAnnotationPresent(Cmd.class))
.filter(t -> t.isAssignableFrom(genericType))
.collect(Collectors.toMap(k -> k.getAnnotation(Cmd.class), k -> k));
Stream<Map.Entry<Cmd, Class<?>>> result = commandClasses.entrySet().stream();
result.filter(c -> c.getKey().parentCommand().equals(""))
.forEach(c -> {
try {
commandMap.put(c.getKey(), (T) c.getValue().newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
result.filter(c -> c.getKey().parentCommand() != "")
.forEach(c -> {
try {
commandMap.put(c.getKey(), (T) c.getValue().newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
return new Registrar<>(allowPermissionInheritance, commandMap);
}
}

View File

@ -0,0 +1,71 @@
package com.sekwah.advancedportals.core.registry;
import com.google.common.collect.ImmutableList;
import com.google.inject.Singleton;
import com.sekwah.advancedportals.core.connector.container.CommandSenderContainer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Singleton
public class Registrar<T extends CommandHandler> implements CommandExecutor, TabCompleter {
//Parent Command, Sub Command, Object
private boolean allowPermissionInheritance;
private Map<Cmd, T> commandMap = new HashMap<>();
protected Registrar(boolean allowPermissionInheritance, Map<Cmd, T> commandMap) {
this.commandMap = commandMap;
}
public boolean isAllowPermissionInheritance() {
return allowPermissionInheritance;
}
public Map<Cmd, T> getCommandMap() {
return commandMap;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
Stream<Map.Entry<Cmd, T>> topLevelCommands = commandMap.entrySet().stream()
.filter(c->c.getKey().name().equals(args[0]) || c.getKey().parentCommand().equals(args[0]));
Optional<Map.Entry<Cmd, T>> results = topLevelCommands.filter(c->c.getKey().name().equals(args[1])).findFirst();
String[] commands = null;
Map.Entry<Cmd, T> key = null;
if (results.isPresent()) {
args[0] = null;
args[1] = null;
commands = new String[]{args[0], args[1]};
key = results.get();
} else {
commands = new String[]{args[0]};
key = topLevelCommands
.filter(c->c.getKey().name().equals(args[0]) && c.getKey().parentCommand().equals(""))
.findFirst().get();
}
if (args[0].length() >= key.getKey().minArgs()) {
} else {
commands = new String[]{args[0], args[1]};
//TODO ????
key.getValue().onCommandFailure(commands, (CommandSenderContainer) sender, new CommandException(ErrorCode.INSUFFICIENT_ARGUMENTS, ""),
ImmutableList.copyOf(Arrays.asList(args)));
}
return false;
}
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
return null;
}
}

View File

@ -1,5 +1,11 @@
package com.sekwah.advancedportals.core.registry;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
//There is no reason to run a double class file when we can just make the main command default out.
@Deprecated()
@Retention(RetentionPolicy.RUNTIME)
public @interface SubCmd {
TYPE parent();

View File

@ -1,4 +1,4 @@
package com.sekwah.advancedportals.core.api.registry;
package com.sekwah.advancedportals.core.registry;
import com.sekwah.advancedportals.core.AdvancedPortalsCore;
import com.sekwah.advancedportals.core.api.commands.SubCommand;

View File

@ -1,4 +1,4 @@
package com.sekwah.advancedportals.core.api.registry;
package com.sekwah.advancedportals.core.registry;
import com.google.inject.Inject;
import com.sekwah.advancedportals.core.AdvancedPortalsCore;

View File

@ -1,4 +1,4 @@
package com.sekwah.advancedportals.core.api.registry;
package com.sekwah.advancedportals.core.registry;
import com.google.inject.Inject;
import com.sekwah.advancedportals.core.AdvancedPortalsCore;

View File

@ -1,4 +1,4 @@
package com.sekwah.advancedportals.core.api.services;
package com.sekwah.advancedportals.core.services;
import com.sekwah.advancedportals.core.api.destination.Destination;
import com.sekwah.advancedportals.core.data.DataTag;

View File

@ -1,4 +1,4 @@
package com.sekwah.advancedportals.core.api.services;
package com.sekwah.advancedportals.core.services;
import com.google.common.collect.ImmutableList;
import com.sekwah.advancedportals.repository.IPortalRepository;

View File

@ -1,4 +1,4 @@
package com.sekwah.advancedportals.core.api.services;
package com.sekwah.advancedportals.core.services;
import com.sekwah.advancedportals.core.data.PlayerTempData;
import com.sekwah.advancedportals.core.data.PortalLocation;

View File

@ -1,5 +1,7 @@
package com.sekwah.advancedportals.repository;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.sekwah.advancedportals.core.api.destination.Destination;
@ -10,11 +12,13 @@ import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@Singleton
public class DestinationRepository implements IDestinationRepository<Destination> {
private final String fileLocation = "";
private Map<String, Destination> destinationCache = new HashMap<String, Destination>();
/*Is there any reason to load it into the array if it's not been used or connected? Q for Sekwah*/