Skip to content

Instantly share code, notes, and snippets.

@mworzala
Last active November 17, 2018 02:00
Show Gist options
  • Save mworzala/17be44aadc346ea7b9011cd54135e6c4 to your computer and use it in GitHub Desktop.
Save mworzala/17be44aadc346ea7b9011cd54135e6c4 to your computer and use it in GitHub Desktop.
CommandRouting
package ca.yomnetwork.skills.command.subcommand.boost;
import ca.yomnetwork.skills.Util;
import ca.yomnetwork.skills.command.SubCommand;
import ca.yomnetwork.skills.core.BoostModule;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import java.util.HashSet;
import java.util.Set;
public class boostTypes implements SubCommand {
private final BoostModule boostModule;
public boostTypes(BoostModule boostModule) {
this.boostModule = boostModule;
}
@Override
public Response onPlayerExecute(Player sender, FileConfiguration lang, String[] args, Set<Character> flags) {
Set<String> uniques = new HashSet<>();
boostModule.getAllBoosts().values().forEach(b -> uniques.addAll(b.getEffects().keySet()));
StringBuilder all = new StringBuilder();
for (String key : uniques)
all.append(" ").append(key).append(",");
all.setLength(all.length()-1);
Util.sendMessageWithEffects(sender, "Boost.Types.Player", "total~" + uniques.size(), "types~" + all.toString().trim());
return Response.OK;
}
@Override
public Response onConsoleExecute(CommandSender sender, FileConfiguration lang, String[] args, Set<Character> flags) {
Set<String> uniques = new HashSet<>();
boostModule.getAllBoosts().values().forEach(b -> uniques.addAll(b.getEffects().keySet()));
StringBuilder all = new StringBuilder();
for (String key : uniques)
all.append(" ").append(key).append(",");
all.setLength(all.length()-1);
Util.sendMessage(sender, "Boost.Types.Console", "total~" + uniques.size(), "types~" + all.toString().trim());
return Response.OK;
}
@Override
public String name() {
return "types";
}
@Override
public String desc() {
return "Fetch all of the exp types used in boosts.";
}
@Override
public String usage() {
return "/sa boost types";
}
@Override
public String perm() {
return "skilladmin.boost.types";
}
@Override
public String[] aliases() {
return new String[]{"type", "t"};
}
}
package ca.yomnetwork.skills.command;
import javafx.util.Pair;
import lombok.Getter;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
public class CRouter {
private final Set<SubCommand> commands = new HashSet<>();
private final Set<CRouter> routers = new HashSet<>();
private final FileConfiguration lang;
@Getter private String[] command;
public CRouter(FileConfiguration lang, String... command) {
this.lang = lang;
this.command = command;
}
public void registerRouter(CRouter router) {
routers.add(router);
}
public void registerCommand(SubCommand sc) {
commands.add(sc);
}
public Set<String> getAllCMD() {
Set<String> cmd = new HashSet<>();
commands.forEach(c -> cmd.add(c.usage()));
routers.forEach(r -> cmd.addAll(r.getAllCMD()));
return cmd;
}
public void onCommand(CommandSender sender, String[] args) {
SubCommand sc = getCommand(args[0]);
if (sc != null) {
Pair<String[], Set<Character>> processed = processArguments(args);
SubCommand.Response response;
if (sender instanceof Player)
response = sc.onPlayerExecute((Player) sender, lang, processed.getKey(), processed.getValue());
else
response = sc.onConsoleExecute(sender, lang, processed.getKey(), processed.getValue());
switch (response) {
case TARGETNOTFOUND:
sender.sendMessage("Target not found");
break;
case INVALIDARGS:
sender.sendMessage("Invalid args: Correct usage is " + sc.usage());
break;
case NOPERMS:
sender.sendMessage("No perms");
break;
case PLAYERONLY:
sender.sendMessage("That command is for players only");
break;
case CONSOLEONLY:
sender.sendMessage("That command is for console only!");
break;
}
return;
}
CRouter router = getRouter(args[0]);
if (router != null) {
String[] argsNew = new String[args.length-1];
System.arraycopy(args, 1, argsNew, 0, args.length - 1);
router.onCommand(sender, argsNew);
return;
}
SubCommand similarCommand = getSimilarCommand(args[0]);
sender.sendMessage(ChatColor.RED + "Command not found. Did you perhaps mean " + similarCommand.name() + "?");
}
private SubCommand getCommand(String command) {
for (SubCommand sc : commands) {
if (command.equalsIgnoreCase(sc.name()))
return sc;
for (String alias : sc.aliases())
if (command.equalsIgnoreCase(alias))
return sc;
}
return null;
}
private CRouter getRouter(String command) {
for (CRouter router : routers)
for (String alias : router.getCommand())
if (command.equalsIgnoreCase(alias))
return router;
return null;
}
private Pair<String[], Set<Character>> processArguments(String[] args) {
Set<Character> flags = new HashSet<>();
for (int i = 1; i < args.length; i++) {
if (args[i].charAt(0) == '-' && args[i].length() == 2) {
flags.add(args[i].charAt(1));
args[i] = "removed_flag";
}
}
int pointer = 0;
String[] argsNew = new String[args.length-flags.size()-1];
for (int i = 1; i < args.length; i++) {
if (!args[i].equalsIgnoreCase("removed_flag")) {
argsNew[pointer] = args[i];
pointer++;
}
}
return new Pair<>(argsNew, flags);
}
private SubCommand getSimilarCommand(String cmd) {
List<String> scNames = new ArrayList<>();
for (SubCommand sc : commands)
scNames.add(sc.name());
Set<String> options = scNames.stream()
.map(String::toLowerCase)
.map(term -> Arrays.stream(term.split(" ")).sorted().collect(Collectors.joining(" ")))
.collect(Collectors.toSet());
Map<String, Integer> cache = new ConcurrentHashMap<>();
return getCommand(options.parallelStream()
.map(String::trim)
.filter(s -> !s.equalsIgnoreCase(cmd))
.min((a, b) -> Integer.compare(
cache.computeIfAbsent(a, k -> levenshteinDist(cmd, k)),
cache.computeIfAbsent(b, k -> levenshteinDist(cmd, k))))
.get());
}
/**
* Credits to https://wikibooks.org for this algorithm.
*/
private int levenshteinDist(CharSequence lhs, CharSequence rhs) {
int len0 = lhs.length() + 1;
int len1 = rhs.length() + 1;
int[] cost = new int[len0];
int[] newcost = new int[len0];
for (int i = 0; i < len0; i++) cost[i] = i;
for (int j = 1; j < len1; j++) {
newcost[0] = j;
for(int i = 1; i < len0; i++) {
int match = (lhs.charAt(i - 1) == rhs.charAt(j - 1)) ? 0 : 1;
int cost_replace = cost[i - 1] + match;
int cost_insert = cost[i] + 1;
int cost_delete = newcost[i - 1] + 1;
newcost[i] = Math.min(Math.min(cost_insert, cost_delete), cost_replace);
}
int[] swap = cost; cost = newcost; newcost = swap;
}
int dist = cost[len0 - 1];
return dist;
}
}
package ca.yomnetwork.skills.command;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import java.util.Set;
public interface SubCommand {
default Response onPlayerExecute(Player sender, FileConfiguration lang, String[] args, Set<Character> flags) {
return Response.CONSOLEONLY;
}
default Response onConsoleExecute(CommandSender sender, FileConfiguration lang, String[] args, Set<Character> flags) {
return Response.PLAYERONLY;
}
String name();
String desc();
String usage();
String perm();
String[] aliases();
enum Response {
OK(),
INVALIDARGS(),
TARGETNOTFOUND(),
NOPERMS(),
CONSOLEONLY(),
PLAYERONLY()
}
}
package ca.yomnetwork.skills.command;
import javafx.util.Pair;
import lombok.Getter;
import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
public class UserCommandRouter {
private final Set<SubCommand> commands = new HashSet<>();
private final Set<UserCommandRouter> routers = new HashSet<>();
private final FileConfiguration lang;
@Getter
private String[] command;
public UserCommandRouter(FileConfiguration lang, String... command) {
this.lang = lang;
this.command = command;
}
public void registerRouter(UserCommandRouter router) {
routers.add(router);
}
public void registerCommand(SubCommand sc) {
commands.add(sc);
}
public Set<String> getAllCMD() {
Set<String> cmd = new HashSet<>();
commands.forEach(c -> cmd.add(c.usage()));
routers.forEach(r -> cmd.addAll(r.getAllCMD()));
return cmd;
}
public void onCommand(CommandSender sender, String[] args) {
if (args.length < 2) {
sender.sendMessage("Help has arrived!");
return;
}
SubCommand sc = getCommand(args[1]);
if (sc != null) {
Pair<String[], Set<Character>> processed = processArguments(args);
SubCommand.Response response;
if (sender instanceof Player)
response = sc.onPlayerExecute((Player) sender, lang, processed.getKey(), processed.getValue());
else
response = sc.onConsoleExecute(sender, lang, processed.getKey(), processed.getValue());
switch (response) {
case TARGETNOTFOUND:
sender.sendMessage("Target not found");
break;
case INVALIDARGS:
sender.sendMessage("Invalid args: Correct usage is " + sc.usage());
break;
case NOPERMS:
sender.sendMessage("No perms");
break;
case PLAYERONLY:
sender.sendMessage("That command is for players only");
break;
case CONSOLEONLY:
sender.sendMessage("That command is for console only!");
break;
}
return;
}
UserCommandRouter router = getRouter(args[1]);
if (router != null) {
//String[] argsNew = new String[args.length-1];
//System.arraycopy(args, 1, argsNew, 0, args.length - 1);
router.onCommand(sender, processArguments(args).getKey());
return;
}
sender.sendMessage(ChatColor.RED + "Command not found. Did you perhaps mean " + getSimilarCommand(args[0]).name() + "?");
}
private SubCommand getCommand(String command) {
for (SubCommand sc : commands) {
if (command.equalsIgnoreCase(sc.name()))
return sc;
for (String alias : sc.aliases())
if (command.equalsIgnoreCase(alias))
return sc;
}
return null;
}
private UserCommandRouter getRouter(String command) {
for (UserCommandRouter router : routers)
for (String alias : router.getCommand())
if (command.equalsIgnoreCase(alias))
return router;
return null;
}
private Pair<String[], Set<Character>> processArguments(String[] args) {
Set<Character> flags = new HashSet<>();
for (int i = 1; i < args.length; i++) {
if (args[i].charAt(0) == '-' && args[i].length() == 2) {
flags.add(args[i].charAt(1));
args[i] = "removed_flag";
}
}
int pointer = 0;
String[] argsNew = new String[args.length-flags.size()-1];
for (int i = 0; i < args.length; i++) {
if (i != 1) {
if (!args[i].equalsIgnoreCase("removed_flag")) {
argsNew[pointer] = args[i];
pointer++;
}
}
}
return new Pair<>(argsNew, flags);
}
private SubCommand getSimilarCommand(String cmd) {
List<String> scNames = new ArrayList<>();
for (SubCommand sc : commands)
scNames.add(sc.name());
Set<String> options = scNames.stream()
.map(String::toLowerCase)
.map(term -> Arrays.stream(term.split(" ")).sorted().collect(Collectors.joining(" ")))
.collect(Collectors.toSet());
Map<String, Integer> cache = new ConcurrentHashMap<>();
return getCommand(options.parallelStream()
.map(String::trim)
.filter(s -> !s.equalsIgnoreCase(cmd))
.min((a, b) -> Integer.compare(
cache.computeIfAbsent(a, k -> levenshteinDist(cmd, k)),
cache.computeIfAbsent(b, k -> levenshteinDist(cmd, k))))
.get());
}
/**
* Credits to https://wikibooks.org for this algorithm.
*/
private int levenshteinDist(CharSequence lhs, CharSequence rhs) {
int len0 = lhs.length() + 1;
int len1 = rhs.length() + 1;
int[] cost = new int[len0];
int[] newcost = new int[len0];
for (int i = 0; i < len0; i++) cost[i] = i;
for (int j = 1; j < len1; j++) {
newcost[0] = j;
for(int i = 1; i < len0; i++) {
int match = (lhs.charAt(i - 1) == rhs.charAt(j - 1)) ? 0 : 1;
int cost_replace = cost[i - 1] + match;
int cost_insert = cost[i] + 1;
int cost_delete = newcost[i - 1] + 1;
newcost[i] = Math.min(Math.min(cost_insert, cost_delete), cost_replace);
}
int[] swap = cost; cost = newcost; newcost = swap;
}
int dist = cost[len0 - 1];
return dist;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment