Last active
November 17, 2018 02:00
-
-
Save mworzala/17be44aadc346ea7b9011cd54135e6c4 to your computer and use it in GitHub Desktop.
CommandRouting
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"}; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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