Database and TabHandler refactoring

This commit is contained in:
Intelli 2025-03-07 20:18:23 -07:00
parent a2076468ad
commit 5b93123ed1
3 changed files with 703 additions and 654 deletions

View file

@ -22,11 +22,11 @@ import net.coreprotect.config.ConfigHandler;
public class TabHandler implements TabCompleter { public class TabHandler implements TabCompleter {
// private static String[] COMMANDS = new String[] { "help", "inspect", "rollback", "restore", "lookup", "purge", "reload", "status", "near", "undo" }; // max 10! // private static String[] COMMANDS = new String[] { "help", "inspect", "rollback", "restore", "lookup", "purge", "reload", "status", "near", "undo" }; // max 10!
private static String[] HELP = new String[] { "inspect", "rollback", "restore", "lookup", "purge", "teleport", "status", "params", "users", "time", "radius", "action", "include", "exclude" }; private static final String[] HELP = new String[] { "inspect", "rollback", "restore", "lookup", "purge", "teleport", "status", "params", "users", "time", "radius", "action", "include", "exclude" };
private static String[] PARAMS = new String[] { "user:", "time:", "radius:", "action:", "include:", "exclude:", "#container" }; private static final String[] PARAMS = new String[] { "user:", "time:", "radius:", "action:", "include:", "exclude:", "#container" };
private static String[] ACTIONS = new String[] { "block", "+block", "-block", "click", "kill", "+container", "-container", "container", "chat", "command", "+inventory", "-inventory", "inventory", "item", "+item", "-item", "sign", "session", "+session", "-session", "username" }; private static final String[] ACTIONS = new String[] { "block", "+block", "-block", "click", "kill", "+container", "-container", "container", "chat", "command", "+inventory", "-inventory", "inventory", "item", "+item", "-item", "sign", "session", "+session", "-session", "username" };
private static String[] NUMBERS = new String[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; private static final String[] NUMBERS = new String[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
private static String[] TIMES = new String[] { "w", "d", "h", "m", "s" }; private static final String[] TIMES = new String[] { "w", "d", "h", "m", "s" };
private static ArrayList<String> materials = null; private static ArrayList<String> materials = null;
@Override @Override
@ -34,124 +34,201 @@ public class TabHandler implements TabCompleter {
if (!(sender instanceof Player) || args.length == 0) { if (!(sender instanceof Player) || args.length == 0) {
return null; return null;
} }
if (args.length == 1) { if (args.length == 1) {
String argument = args[0].toLowerCase(Locale.ROOT); return getFirstLevelCompletions(sender, args[0]);
List<String> completions = new ArrayList<>();
if (sender.hasPermission("coreprotect.help")) {
completions.add("help");
}
if (sender.hasPermission("coreprotect.inspect")) {
completions.add("inspect");
}
if (sender.hasPermission("coreprotect.rollback")) {
completions.add("rollback");
}
if (sender.hasPermission("coreprotect.restore")) {
completions.add("restore");
}
if (sender.hasPermission("coreprotect.lookup")) {
completions.add("lookup");
}
if (sender.hasPermission("coreprotect.purge")) {
completions.add("purge");
}
if (sender.hasPermission("coreprotect.reload")) {
completions.add("reload");
}
if (sender.hasPermission("coreprotect.status")) {
completions.add("status");
}
if (sender.hasPermission("coreprotect.lookup.near")) {
completions.add("near");
}
if (sender.hasPermission("coreprotect.restore")) {
completions.add("undo");
} }
return StringUtil.copyPartialMatches(argument, completions, new ArrayList<>(completions.size()));
}
else if (args.length > 1) {
String argument0 = args[0].toLowerCase(Locale.ROOT); String argument0 = args[0].toLowerCase(Locale.ROOT);
String argument1 = args[1].toLowerCase(Locale.ROOT);
String currentArg = args[args.length - 1].toLowerCase(Locale.ROOT).trim(); String currentArg = args[args.length - 1].toLowerCase(Locale.ROOT).trim();
String lastArg = args[args.length - 2].toLowerCase(Locale.ROOT).trim(); String lastArg = args.length > 1 ? args[args.length - 2].toLowerCase(Locale.ROOT).trim() : "";
boolean hasUser = false; ParamState paramState = getParamState(args);
boolean hasAction = false;
boolean hasInclude = false;
boolean hasExclude = false;
boolean hasRadius = false;
boolean hasTime = false;
boolean hasContainer = false;
boolean hasCount = false;
boolean hasPreview = false;
boolean hasPage = false;
boolean validContainer = false;
boolean pageLookup = false;
if (ConfigHandler.lookupType.get(sender.getName()) != null && ConfigHandler.lookupPage.get(sender.getName()) != null) { // Handle param-specific completions
pageLookup = true; if (isActionParam(lastArg, currentArg) && hasLookupPermission(sender)) {
return handleActionParamCompletions(currentArg, lastArg);
}
else if (isUserParam(lastArg, currentArg) && hasLookupPermission(sender)) {
return handleUserParamCompletions(currentArg, lastArg);
}
else if (isTimeParam(lastArg, currentArg) && hasTimePermission(sender)) {
return handleTimeParamCompletions(currentArg, lastArg);
}
else if (isPageParam(lastArg, currentArg) && hasPagePermission(sender)) {
return handlePageParamCompletions(currentArg, lastArg);
}
else if (isRadiusParam(lastArg, currentArg) && hasRadiusPermission(sender)) {
return handleRadiusParamCompletions(currentArg, lastArg, argument0);
}
else if (isMaterialParam(lastArg, currentArg) && hasLookupPermission(sender)) {
return handleMaterialParamCompletions(currentArg, lastArg);
}
else if (args.length == 2) {
return handleSecondArgCompletions(sender, argument0, args[1], paramState);
}
else if (args.length == 3 && argument0.equals("purge") && sender.hasPermission("coreprotect.purge")) {
return handlePurgeThirdArgCompletions(args[1], args[2]);
}
else if (hasLookupCommand(argument0, sender) && (!argument0.equals("l") && !argument0.equals("lookup") || !paramState.hasPage)) {
return handleGenericLookupCompletions(argument0, currentArg, paramState);
}
return Arrays.asList("");
}
private List<String> getFirstLevelCompletions(CommandSender sender, String argument) {
String arg = argument.toLowerCase(Locale.ROOT);
List<String> completions = new ArrayList<>();
addCompletionIfPermitted(sender, "coreprotect.help", "help", completions);
addCompletionIfPermitted(sender, "coreprotect.inspect", "inspect", completions);
addCompletionIfPermitted(sender, "coreprotect.rollback", "rollback", completions);
addCompletionIfPermitted(sender, "coreprotect.restore", "restore", completions);
addCompletionIfPermitted(sender, "coreprotect.lookup", "lookup", completions);
addCompletionIfPermitted(sender, "coreprotect.purge", "purge", completions);
addCompletionIfPermitted(sender, "coreprotect.reload", "reload", completions);
addCompletionIfPermitted(sender, "coreprotect.status", "status", completions);
addCompletionIfPermitted(sender, "coreprotect.lookup.near", "near", completions);
addCompletionIfPermitted(sender, "coreprotect.restore", "undo", completions);
return StringUtil.copyPartialMatches(arg, completions, new ArrayList<>(completions.size()));
}
private void addCompletionIfPermitted(CommandSender sender, String permission, String completion, List<String> completions) {
if (sender.hasPermission(permission)) {
completions.add(completion);
}
}
private boolean hasLookupPermission(CommandSender sender) {
return sender.hasPermission("coreprotect.lookup") || sender.hasPermission("coreprotect.rollback") || sender.hasPermission("coreprotect.restore");
}
private boolean hasTimePermission(CommandSender sender) {
return hasLookupPermission(sender) || sender.hasPermission("coreprotect.purge");
}
private boolean hasRadiusPermission(CommandSender sender) {
return hasTimePermission(sender);
}
private boolean hasPagePermission(CommandSender sender) {
return sender.hasPermission("coreprotect.lookup") || sender.hasPermission("coreprotect.lookup.near") || sender.hasPermission("coreprotect.inspect");
}
private boolean hasLookupCommand(String cmd, CommandSender sender) {
return (sender.hasPermission("coreprotect.lookup") && (cmd.equals("l") || cmd.equals("lookup"))) || (sender.hasPermission("coreprotect.rollback") && (cmd.equals("rollback") || cmd.equals("rb") || cmd.equals("ro"))) || (sender.hasPermission("coreprotect.restore") && (cmd.equals("restore") || cmd.equals("rs") || cmd.equals("re")));
}
private boolean isActionParam(String lastArg, String currentArg) {
return lastArg.equals("a:") || lastArg.equals("action:") || currentArg.startsWith("a:") || currentArg.startsWith("action:");
}
private boolean isUserParam(String lastArg, String currentArg) {
return lastArg.equals("u:") || lastArg.equals("user:") || lastArg.equals("users:") || lastArg.equals("p:") || currentArg.startsWith("u:") || currentArg.startsWith("user:") || currentArg.startsWith("users:") || currentArg.startsWith("p:");
}
private boolean isTimeParam(String lastArg, String currentArg) {
return lastArg.equals("t:") || lastArg.equals("time:") || currentArg.startsWith("t:") || currentArg.startsWith("time:");
}
private boolean isPageParam(String lastArg, String currentArg) {
return lastArg.equals("page:") || currentArg.startsWith("page:");
}
private boolean isRadiusParam(String lastArg, String currentArg) {
return lastArg.equals("r:") || lastArg.equals("radius:") || currentArg.startsWith("r:") || currentArg.startsWith("radius:");
}
private boolean isMaterialParam(String lastArg, String currentArg) {
return lastArg.equals("i:") || lastArg.equals("include:") || lastArg.equals("item:") || lastArg.equals("items:") || lastArg.equals("b:") || lastArg.equals("block:") || lastArg.equals("blocks:") || currentArg.startsWith("i:") || currentArg.startsWith("include:") || currentArg.startsWith("item:") || currentArg.startsWith("items:") || currentArg.startsWith("b:") || currentArg.startsWith("block:") || currentArg.startsWith("blocks:") || lastArg.equals("e:") || lastArg.equals("exclude:") || currentArg.startsWith("e:") || currentArg.startsWith("exclude:");
}
private static class ParamState {
boolean hasUser;
boolean hasAction;
boolean hasInclude;
boolean hasExclude;
boolean hasRadius;
boolean hasTime;
boolean hasContainer;
boolean hasCount;
boolean hasPreview;
boolean hasPage;
boolean validContainer;
boolean pageLookup;
}
private ParamState getParamState(String[] args) {
ParamState state = new ParamState();
if (ConfigHandler.lookupType.get(args[0]) != null && ConfigHandler.lookupPage.get(args[0]) != null) {
state.pageLookup = true;
} }
for (int i = 1; i < args.length; i++) { for (int i = 1; i < args.length; i++) {
String arg = args[i].toLowerCase(Locale.ROOT); String arg = args[i].toLowerCase(Locale.ROOT);
if (arg.equals("#container")) { if (arg.equals("#container")) {
hasContainer = true; state.hasContainer = true;
} }
else if (arg.equals("#count") || arg.equals("#sum")) { else if (arg.equals("#count") || arg.equals("#sum")) {
hasCount = true; state.hasCount = true;
} }
else if (arg.equals("#preview")) { else if (arg.equals("#preview")) {
hasPreview = true; state.hasPreview = true;
} }
else if ((!arg.contains(":") && !args[i - 1].contains(":") && args.length > (i + 1)) || arg.contains("u:") || arg.contains("user:") || arg.contains("users:") || arg.contains("p:")) { else if ((!arg.contains(":") && !args[i - 1].contains(":") && args.length > (i + 1)) || arg.contains("u:") || arg.contains("user:") || arg.contains("users:") || arg.contains("p:")) {
hasUser = true; state.hasUser = true;
} }
else if (arg.contains("page:")) { else if (arg.contains("page:")) {
hasPage = true; state.hasPage = true;
} }
else if (arg.contains("a:") || arg.contains("action:")) { else if (arg.contains("a:") || arg.contains("action:")) {
hasAction = true; state.hasAction = true;
} }
else if (arg.contains("i:") || arg.contains("include:") || arg.contains("item:") || arg.contains("items:") || arg.contains("b:") || arg.contains("block:") || arg.contains("blocks:")) { else if (arg.contains("i:") || arg.contains("include:") || arg.contains("item:") || arg.contains("items:") || arg.contains("b:") || arg.contains("block:") || arg.contains("blocks:")) {
hasInclude = true; state.hasInclude = true;
} }
else if (arg.contains("t:") || arg.contains("time:")) { else if (arg.contains("t:") || arg.contains("time:")) {
hasTime = true; state.hasTime = true;
} }
else if (arg.contains("e:") || arg.contains("exclude:")) { else if (arg.contains("e:") || arg.contains("exclude:")) {
hasExclude = true; state.hasExclude = true;
} }
else if (arg.contains("r:") || arg.contains("radius:")) { else if (arg.contains("r:") || arg.contains("radius:")) {
hasRadius = true; state.hasRadius = true;
} }
} }
if (!hasContainer) { if (!state.hasContainer) {
if (ConfigHandler.lookupType.get(sender.getName()) != null) { if (ConfigHandler.lookupType.get(args[0]) != null) {
int lookupType = ConfigHandler.lookupType.get(sender.getName()); int lookupType = ConfigHandler.lookupType.get(args[0]);
if (lookupType == 1) { if (lookupType == 1) {
validContainer = true; state.validContainer = true;
} }
else if (lookupType == 5) { else if (lookupType == 5) {
if (ConfigHandler.lookupUlist.get(sender.getName()).contains("#container")) { if (ConfigHandler.lookupUlist.get(args[0]).contains("#container")) {
validContainer = true; state.validContainer = true;
} }
} }
} }
} }
if ((lastArg.equals("a:") || lastArg.equals("action:")) && (sender.hasPermission("coreprotect.lookup") || sender.hasPermission("coreprotect.rollback") || sender.hasPermission("coreprotect.restore"))) { return state;
List<String> completions = new ArrayList<>(Arrays.asList(ACTIONS));
return StringUtil.copyPartialMatches(currentArg, completions, new ArrayList<>(completions.size()));
} }
else if ((currentArg.startsWith("a:") || currentArg.startsWith("action:")) && (sender.hasPermission("coreprotect.lookup") || sender.hasPermission("coreprotect.rollback") || sender.hasPermission("coreprotect.restore"))) {
private List<String> handleActionParamCompletions(String currentArg, String lastArg) {
String arg = ""; String arg = "";
String filter = lastArg;
if (currentArg.contains(":")) {
String[] split = currentArg.split(":", 2); String[] split = currentArg.split(":", 2);
String filter = split[0] + ":"; filter = split[0] + ":";
if (split.length > 1) { if (split.length > 1) {
arg = split[1]; arg = split[1];
} }
}
List<String> completions = new ArrayList<>(Arrays.asList(ACTIONS)); List<String> completions = new ArrayList<>(Arrays.asList(ACTIONS));
for (int index = 0; index < completions.size(); index++) { for (int index = 0; index < completions.size(); index++) {
@ -159,10 +236,12 @@ public class TabHandler implements TabCompleter {
} }
return StringUtil.copyPartialMatches(filter + arg, completions, new ArrayList<>(completions.size())); return StringUtil.copyPartialMatches(filter + arg, completions, new ArrayList<>(completions.size()));
} }
else if ((lastArg.equals("u:") || lastArg.equals("user:") || lastArg.equals("users:") || lastArg.equals("p:")) && (sender.hasPermission("coreprotect.lookup") || sender.hasPermission("coreprotect.rollback") || sender.hasPermission("coreprotect.restore"))) {
private List<String> handleUserParamCompletions(String currentArg, String lastArg) {
if (lastArg.equals("u:") || lastArg.equals("user:") || lastArg.equals("users:") || lastArg.equals("p:")) {
return null; return null;
} }
else if ((currentArg.startsWith("u:") || currentArg.startsWith("user:") || currentArg.startsWith("users:") || currentArg.startsWith("p:")) && (sender.hasPermission("coreprotect.lookup") || sender.hasPermission("coreprotect.rollback") || sender.hasPermission("coreprotect.restore"))) {
String arg = ""; String arg = "";
String[] split = currentArg.split(":", 2); String[] split = currentArg.split(":", 2);
String filter = split[0] + ":"; String filter = split[0] + ":";
@ -171,13 +250,15 @@ public class TabHandler implements TabCompleter {
} }
List<String> completions = Bukkit.getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList()); List<String> completions = Bukkit.getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList());
for (int index = 0; index < completions.size(); index++) { for (int index = 0; index < completions.size(); index++) {
completions.set(index, filter + completions.get(index)); completions.set(index, filter + completions.get(index));
} }
return StringUtil.copyPartialMatches(filter + arg, completions, new ArrayList<>(completions.size())); return StringUtil.copyPartialMatches(filter + arg, completions, new ArrayList<>(completions.size()));
} }
else if ((lastArg.equals("t:") || lastArg.equals("time:") || currentArg.startsWith("t:") || currentArg.startsWith("time:")) && (sender.hasPermission("coreprotect.lookup") || sender.hasPermission("coreprotect.rollback") || sender.hasPermission("coreprotect.restore") || sender.hasPermission("coreprotect.purge"))) {
private List<String> handleTimeParamCompletions(String currentArg, String lastArg) {
String filter = lastArg; String filter = lastArg;
String arg = ""; String arg = "";
if (currentArg.contains(":")) { if (currentArg.contains(":")) {
@ -205,7 +286,6 @@ public class TabHandler implements TabCompleter {
if (addNumbers) { if (addNumbers) {
completions.addAll(Arrays.asList(NUMBERS)); completions.addAll(Arrays.asList(NUMBERS));
} }
} }
completions = new ArrayList<>(completions); completions = new ArrayList<>(completions);
@ -215,7 +295,8 @@ public class TabHandler implements TabCompleter {
return StringUtil.copyPartialMatches(filter + arg, completions, new ArrayList<>(completions.size())); return StringUtil.copyPartialMatches(filter + arg, completions, new ArrayList<>(completions.size()));
} }
else if ((lastArg.equals("page:") || currentArg.startsWith("page:")) && (sender.hasPermission("coreprotect.lookup") || sender.hasPermission("coreprotect.lookup.near") || sender.hasPermission("coreprotect.inspect"))) {
private List<String> handlePageParamCompletions(String currentArg, String lastArg) {
String filter = lastArg; String filter = lastArg;
String arg = ""; String arg = "";
if (currentArg.contains(":")) { if (currentArg.contains(":")) {
@ -242,8 +323,11 @@ public class TabHandler implements TabCompleter {
} }
return StringUtil.copyPartialMatches(filter + arg, completions, new ArrayList<>(completions.size())); return StringUtil.copyPartialMatches(filter + arg, completions, new ArrayList<>(completions.size()));
} }
return null;
} }
else if ((lastArg.equals("r:") || lastArg.equals("radius:") || currentArg.startsWith("r:") || currentArg.startsWith("radius:")) && (sender.hasPermission("coreprotect.lookup") || sender.hasPermission("coreprotect.rollback") || sender.hasPermission("coreprotect.restore") || sender.hasPermission("coreprotect.purge"))) {
private List<String> handleRadiusParamCompletions(String currentArg, String lastArg, String baseCommand) {
String filter = lastArg; String filter = lastArg;
String arg = ""; String arg = "";
if (currentArg.contains(":")) { if (currentArg.contains(":")) {
@ -258,7 +342,7 @@ public class TabHandler implements TabCompleter {
arg = currentArg; arg = currentArg;
} }
if (!argument0.equals("purge") && arg.chars().allMatch(Character::isDigit)) { if (!baseCommand.equals("purge") && arg.chars().allMatch(Character::isDigit)) {
List<String> completions = new ArrayList<>(Arrays.asList(NUMBERS)); List<String> completions = new ArrayList<>(Arrays.asList(NUMBERS));
if (arg.length() < 2) { if (arg.length() < 2) {
for (int index = 0; index < completions.size(); index++) { for (int index = 0; index < completions.size(); index++) {
@ -267,13 +351,13 @@ public class TabHandler implements TabCompleter {
} }
return StringUtil.copyPartialMatches(filter + arg, completions, new ArrayList<>(completions.size())); return StringUtil.copyPartialMatches(filter + arg, completions, new ArrayList<>(completions.size()));
} }
else if (argument0.equals("purge") || arg.startsWith("#")) { else if (baseCommand.equals("purge") || arg.startsWith("#")) {
ArrayList<String> params = new ArrayList<>(); ArrayList<String> params = new ArrayList<>();
params.add("#global"); params.add("#global");
if (!argument0.equals("purge") && sender.getServer().getPluginManager().getPlugin("WorldEdit") != null) { if (!baseCommand.equals("purge") && Bukkit.getServer().getPluginManager().getPlugin("WorldEdit") != null) {
params.add("#worldedit"); params.add("#worldedit");
} }
List<World> worlds = sender.getServer().getWorlds(); List<World> worlds = Bukkit.getServer().getWorlds();
for (World world : worlds) { for (World world : worlds) {
params.add("#" + world.getName()); params.add("#" + world.getName());
} }
@ -283,8 +367,11 @@ public class TabHandler implements TabCompleter {
} }
return StringUtil.copyPartialMatches(filter + arg, completions, new ArrayList<>(completions.size())); return StringUtil.copyPartialMatches(filter + arg, completions, new ArrayList<>(completions.size()));
} }
return null;
} }
else if ((sender.hasPermission("coreprotect.lookup") || sender.hasPermission("coreprotect.rollback") || sender.hasPermission("coreprotect.restore")) && (lastArg.equals("i:") || lastArg.equals("include:") || lastArg.equals("item:") || lastArg.equals("items:") || lastArg.equals("b:") || lastArg.equals("block:") || lastArg.equals("blocks:") || currentArg.startsWith("i:") || currentArg.startsWith("include:") || currentArg.startsWith("item:") || currentArg.startsWith("items:") || currentArg.startsWith("b:") || currentArg.startsWith("block:") || currentArg.startsWith("blocks:") || lastArg.equals("e:") || lastArg.equals("exclude:") || currentArg.startsWith("e:") || currentArg.startsWith("exclude:"))) {
private List<String> handleMaterialParamCompletions(String currentArg, String lastArg) {
String filter = lastArg; String filter = lastArg;
String arg = ""; String arg = "";
if (currentArg.contains(":")) { if (currentArg.contains(":")) {
@ -299,6 +386,16 @@ public class TabHandler implements TabCompleter {
arg = currentArg; arg = currentArg;
} }
initializeMaterialsIfNeeded();
List<String> completions = new ArrayList<>(materials);
for (int index = 0; index < completions.size(); index++) {
completions.set(index, filter + completions.get(index));
}
return StringUtil.copyPartialMatches(filter + arg, completions, new ArrayList<>(completions.size()));
}
private void initializeMaterialsIfNeeded() {
if (materials == null) { if (materials == null) {
List<Material> addList = Arrays.asList(Material.ARMOR_STAND); List<Material> addList = Arrays.asList(Material.ARMOR_STAND);
List<Material> excludeList = Arrays.asList(); List<Material> excludeList = Arrays.asList();
@ -324,15 +421,12 @@ public class TabHandler implements TabCompleter {
materials = new ArrayList<>(materialList); materials = new ArrayList<>(materialList);
} }
List<String> completions = new ArrayList<>(materials);
for (int index = 0; index < completions.size(); index++) {
completions.set(index, filter + completions.get(index));
} }
return StringUtil.copyPartialMatches(filter + arg, completions, new ArrayList<>(completions.size()));
} private List<String> handleSecondArgCompletions(CommandSender sender, String cmd0, String cmd1, ParamState paramState) {
else if (args.length == 2) { String argument0 = cmd0.toLowerCase(Locale.ROOT);
String argument1 = cmd1.toLowerCase(Locale.ROOT);
if (argument0.equals("help") && sender.hasPermission("coreprotect.help")) { if (argument0.equals("help") && sender.hasPermission("coreprotect.help")) {
List<String> completions = new ArrayList<>(Arrays.asList(HELP)); List<String> completions = new ArrayList<>(Arrays.asList(HELP));
return StringUtil.copyPartialMatches(argument1, completions, new ArrayList<>(completions.size())); return StringUtil.copyPartialMatches(argument1, completions, new ArrayList<>(completions.size()));
@ -341,68 +435,69 @@ public class TabHandler implements TabCompleter {
List<String> completions = new ArrayList<>(Arrays.asList("t:", "r:", "i:")); List<String> completions = new ArrayList<>(Arrays.asList("t:", "r:", "i:"));
return StringUtil.copyPartialMatches(argument1, completions, new ArrayList<>(completions.size())); return StringUtil.copyPartialMatches(argument1, completions, new ArrayList<>(completions.size()));
} }
else if ((sender.hasPermission("coreprotect.lookup") && (argument0.equals("l") || argument0.equals("lookup"))) || (sender.hasPermission("coreprotect.rollback") && (argument0.equals("rollback") || argument0.equals("rb") || argument0.equals("ro"))) || (sender.hasPermission("coreprotect.restore") && (argument0.equals("restore") || argument0.equals("rs") || argument0.equals("re")))) { else if (hasLookupCommand(argument0, sender)) {
List<String> completions = new ArrayList<>(filterParams(true, argument0, argument1, hasUser, hasAction, hasInclude, hasExclude, hasRadius, hasTime, hasContainer, hasCount, hasPreview, pageLookup, validContainer)); List<String> completions = new ArrayList<>(filterParams(true, argument0, argument1, paramState));
completions.addAll(Bukkit.getOnlinePlayers().stream().filter(player -> player.getName().toLowerCase(Locale.ROOT).startsWith(argument1)).map(Player::getName).collect(Collectors.toList())); completions.addAll(Bukkit.getOnlinePlayers().stream().filter(player -> player.getName().toLowerCase(Locale.ROOT).startsWith(argument1)).map(Player::getName).collect(Collectors.toList()));
return StringUtil.copyPartialMatches(argument1, completions, new ArrayList<>(completions.size())); return StringUtil.copyPartialMatches(argument1, completions, new ArrayList<>(completions.size()));
} }
return null;
} }
else if (args.length == 3 && argument0.equals("purge") && sender.hasPermission("coreprotect.purge")) {
private List<String> handlePurgeThirdArgCompletions(String arg1, String arg2) {
String argument1 = arg1.toLowerCase(Locale.ROOT);
String argument2 = arg2.toLowerCase(Locale.ROOT);
if (argument1.startsWith("t:")) { if (argument1.startsWith("t:")) {
List<String> completions = new ArrayList<>(Arrays.asList("r:", "i:")); List<String> completions = new ArrayList<>(Arrays.asList("r:", "i:"));
return StringUtil.copyPartialMatches(args[2].toLowerCase(Locale.ROOT), completions, new ArrayList<>(completions.size())); return StringUtil.copyPartialMatches(argument2, completions, new ArrayList<>(completions.size()));
} }
else if (argument1.startsWith("r:") || argument1.startsWith("i:")) { else if (argument1.startsWith("r:") || argument1.startsWith("i:")) {
List<String> completions = new ArrayList<>(Arrays.asList("t:")); List<String> completions = new ArrayList<>(Arrays.asList("t:"));
return StringUtil.copyPartialMatches(args[2].toLowerCase(Locale.ROOT), completions, new ArrayList<>(completions.size())); return StringUtil.copyPartialMatches(argument2, completions, new ArrayList<>(completions.size()));
} }
return Arrays.asList(""); return Arrays.asList("");
} }
else if ((sender.hasPermission("coreprotect.lookup") && (argument0.equals("l") || argument0.equals("lookup"))) || (sender.hasPermission("coreprotect.rollback") && (argument0.equals("rollback") || argument0.equals("rb") || argument0.equals("ro"))) || (sender.hasPermission("coreprotect.restore") && (argument0.equals("restore") || argument0.equals("rs") || argument0.equals("re")))) {
if ((!argument0.equals("l") && !argument0.equals("lookup")) || !hasPage) { private List<String> handleGenericLookupCompletions(String cmd, String currentArg, ParamState paramState) {
ArrayList<String> params = filterParams(false, argument0, currentArg, hasUser, hasAction, hasInclude, hasExclude, hasRadius, hasTime, hasContainer, hasCount, hasPreview, pageLookup, validContainer); ArrayList<String> params = filterParams(false, cmd, currentArg, paramState);
List<String> completions = new ArrayList<>(params); List<String> completions = new ArrayList<>(params);
return StringUtil.copyPartialMatches(currentArg, completions, new ArrayList<>(completions.size())); return StringUtil.copyPartialMatches(currentArg, completions, new ArrayList<>(completions.size()));
} }
}
}
return Arrays.asList(""); private ArrayList<String> filterParams(boolean firstParam, String lastArgument, String argument, ParamState state) {
}
private ArrayList<String> filterParams(boolean firstParam, String lastArgument, String argument, boolean hasUser, boolean hasAction, boolean hasInclude, boolean hasExclude, boolean hasRadius, boolean hasTime, boolean hasContainer, boolean hasCount, boolean hasPreview, boolean pageLookup, boolean validContainer) {
ArrayList<String> params = new ArrayList<>(); ArrayList<String> params = new ArrayList<>();
for (String param : PARAMS) { for (String param : PARAMS) {
if (param.equals("user:") && !hasUser) { if (param.equals("user:") && !state.hasUser) {
params.add(param); params.add(param);
} }
else if (param.equals("action:") && !hasAction) { else if (param.equals("action:") && !state.hasAction) {
params.add(param); params.add(param);
} }
else if (param.equals("include:") && !hasInclude) { else if (param.equals("include:") && !state.hasInclude) {
params.add(param); params.add(param);
} }
else if (param.equals("exclude:") && !hasExclude) { else if (param.equals("exclude:") && !state.hasExclude) {
params.add(param); params.add(param);
} }
else if (param.equals("radius:") && !hasRadius) { else if (param.equals("radius:") && !state.hasRadius) {
params.add(param); params.add(param);
} }
else if (param.equals("time:") && !hasTime) { else if (param.equals("time:") && !state.hasTime) {
params.add(param); params.add(param);
} }
else if (param.equals("#container") && !hasContainer && !hasRadius && validContainer) { else if (param.equals("#container") && !state.hasContainer && !state.hasRadius && state.validContainer) {
params.add(param); params.add(param);
} }
} }
if (firstParam && pageLookup && (lastArgument.equals("l") || lastArgument.equals("lookup"))) { if (firstParam && state.pageLookup && (lastArgument.equals("l") || lastArgument.equals("lookup"))) {
params.add("page:"); params.add("page:");
} }
else if (!firstParam && argument.startsWith("#")) { else if (!firstParam && argument.startsWith("#")) {
if (!hasCount) { if (!state.hasCount) {
params.add("#count"); params.add("#count");
} }
if (!hasPreview) { if (!state.hasPreview) {
params.add("#preview"); params.add("#preview");
} }
} }

View file

@ -8,8 +8,10 @@ import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
@ -44,6 +46,26 @@ public class Database extends Queue {
public static final int BLOCKDATA = 12; public static final int BLOCKDATA = 12;
public static final int ITEM = 13; public static final int ITEM = 13;
private static final Map<Integer, String> SQL_QUERIES = new HashMap<>();
static {
// Initialize SQL queries for different table types
SQL_QUERIES.put(SIGN, "INSERT INTO %sprefix%sign (time, user, wid, x, y, z, action, color, color_secondary, data, waxed, face, line_1, line_2, line_3, line_4, line_5, line_6, line_7, line_8) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
SQL_QUERIES.put(BLOCK, "INSERT INTO %sprefix%block (time, user, wid, x, y, z, type, data, meta, blockdata, action, rolled_back) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
SQL_QUERIES.put(SKULL, "INSERT INTO %sprefix%skull (time, owner, skin) VALUES (?, ?, ?)");
SQL_QUERIES.put(CONTAINER, "INSERT INTO %sprefix%container (time, user, wid, x, y, z, type, data, amount, metadata, action, rolled_back) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
SQL_QUERIES.put(ITEM, "INSERT INTO %sprefix%item (time, user, wid, x, y, z, type, data, amount, action, rolled_back) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
SQL_QUERIES.put(WORLD, "INSERT INTO %sprefix%world (id, world) VALUES (?, ?)");
SQL_QUERIES.put(CHAT, "INSERT INTO %sprefix%chat (time, user, wid, x, y, z, message) VALUES (?, ?, ?, ?, ?, ?, ?)");
SQL_QUERIES.put(COMMAND, "INSERT INTO %sprefix%command (time, user, wid, x, y, z, message) VALUES (?, ?, ?, ?, ?, ?, ?)");
SQL_QUERIES.put(SESSION, "INSERT INTO %sprefix%session (time, user, wid, x, y, z, action) VALUES (?, ?, ?, ?, ?, ?, ?)");
SQL_QUERIES.put(ENTITY, "INSERT INTO %sprefix%entity (time, data) VALUES (?, ?)");
SQL_QUERIES.put(MATERIAL, "INSERT INTO %sprefix%material_map (id, material) VALUES (?, ?)");
SQL_QUERIES.put(ART, "INSERT INTO %sprefix%art_map (id, art) VALUES (?, ?)");
SQL_QUERIES.put(ENTITY_MAP, "INSERT INTO %sprefix%entity_map (id, entity) VALUES (?, ?)");
SQL_QUERIES.put(BLOCKDATA, "INSERT INTO %sprefix%blockdata_map (id, data) VALUES (?, ?)");
}
public static void beginTransaction(Statement statement, boolean isMySQL) { public static void beginTransaction(Statement statement, boolean isMySQL) {
Consumer.transacting = true; Consumer.transacting = true;
@ -133,8 +155,7 @@ public class Database extends Queue {
} }
public static Connection getConnection(boolean onlyCheckTransacting) { public static Connection getConnection(boolean onlyCheckTransacting) {
// Previously 250ms; long consumer commit time may be due to batching // Previously 250ms; long consumer commit time may be due to batching (investigate removing batching for SQLite connections)
// TODO: Investigate, potentially remove batching for SQLite connections
return getConnection(false, false, onlyCheckTransacting, 1000); return getConnection(false, false, onlyCheckTransacting, 1000);
} }
@ -220,64 +241,10 @@ public class Database extends Queue {
public static PreparedStatement prepareStatement(Connection connection, int type, boolean keys) { public static PreparedStatement prepareStatement(Connection connection, int type, boolean keys) {
PreparedStatement preparedStatement = null; PreparedStatement preparedStatement = null;
try { try {
String signInsert = "INSERT INTO " + ConfigHandler.prefix + "sign (time, user, wid, x, y, z, action, color, color_secondary, data, waxed, face, line_1, line_2, line_3, line_4, line_5, line_6, line_7, line_8) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; String query = SQL_QUERIES.get(type);
String blockInsert = "INSERT INTO " + ConfigHandler.prefix + "block (time, user, wid, x, y, z, type, data, meta, blockdata, action, rolled_back) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; if (query != null) {
String skullInsert = "INSERT INTO " + ConfigHandler.prefix + "skull (time, owner, skin) VALUES (?, ?, ?)"; query = query.replace("%sprefix%", ConfigHandler.prefix);
String containerInsert = "INSERT INTO " + ConfigHandler.prefix + "container (time, user, wid, x, y, z, type, data, amount, metadata, action, rolled_back) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; preparedStatement = prepareStatement(connection, query, keys);
String itemInsert = "INSERT INTO " + ConfigHandler.prefix + "item (time, user, wid, x, y, z, type, data, amount, action, rolled_back) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
String worldInsert = "INSERT INTO " + ConfigHandler.prefix + "world (id, world) VALUES (?, ?)";
String chatInsert = "INSERT INTO " + ConfigHandler.prefix + "chat (time, user, wid, x, y, z, message) VALUES (?, ?, ?, ?, ?, ?, ?)";
String commandInsert = "INSERT INTO " + ConfigHandler.prefix + "command (time, user, wid, x, y, z, message) VALUES (?, ?, ?, ?, ?, ?, ?)";
String sessionInsert = "INSERT INTO " + ConfigHandler.prefix + "session (time, user, wid, x, y, z, action) VALUES (?, ?, ?, ?, ?, ?, ?)";
String entityInsert = "INSERT INTO " + ConfigHandler.prefix + "entity (time, data) VALUES (?, ?)";
String materialInsert = "INSERT INTO " + ConfigHandler.prefix + "material_map (id, material) VALUES (?, ?)";
String artInsert = "INSERT INTO " + ConfigHandler.prefix + "art_map (id, art) VALUES (?, ?)";
String entityMapInsert = "INSERT INTO " + ConfigHandler.prefix + "entity_map (id, entity) VALUES (?, ?)";
String blockdataInsert = "INSERT INTO " + ConfigHandler.prefix + "blockdata_map (id, data) VALUES (?, ?)";
switch (type) {
case SIGN:
preparedStatement = prepareStatement(connection, signInsert, keys);
break;
case BLOCK:
preparedStatement = prepareStatement(connection, blockInsert, keys);
break;
case SKULL:
preparedStatement = prepareStatement(connection, skullInsert, keys);
break;
case CONTAINER:
preparedStatement = prepareStatement(connection, containerInsert, keys);
break;
case ITEM:
preparedStatement = prepareStatement(connection, itemInsert, keys);
break;
case WORLD:
preparedStatement = prepareStatement(connection, worldInsert, keys);
break;
case CHAT:
preparedStatement = prepareStatement(connection, chatInsert, keys);
break;
case COMMAND:
preparedStatement = prepareStatement(connection, commandInsert, keys);
break;
case SESSION:
preparedStatement = prepareStatement(connection, sessionInsert, keys);
break;
case ENTITY:
preparedStatement = prepareStatement(connection, entityInsert, keys);
break;
case MATERIAL:
preparedStatement = prepareStatement(connection, materialInsert, keys);
break;
case ART:
preparedStatement = prepareStatement(connection, artInsert, keys);
break;
case ENTITY_MAP:
preparedStatement = prepareStatement(connection, entityMapInsert, keys);
break;
case BLOCKDATA:
preparedStatement = prepareStatement(connection, blockdataInsert, keys);
break;
} }
} }
catch (Exception e) { catch (Exception e) {
@ -339,48 +306,26 @@ public class Database extends Queue {
} }
} }
private static final List<String> DATABASE_TABLES = Arrays.asList("art_map", "block", "chat", "command", "container", "item", "database_lock", "entity", "entity_map", "material_map", "blockdata_map", "session", "sign", "skull", "user", "username_log", "version", "world");
public static void createDatabaseTables(String prefix, Connection forceConnection, boolean mySQL, boolean purge) { public static void createDatabaseTables(String prefix, Connection forceConnection, boolean mySQL, boolean purge) {
ConfigHandler.databaseTables.clear(); ConfigHandler.databaseTables.clear();
ConfigHandler.databaseTables.addAll(Arrays.asList("art_map", "block", "chat", "command", "container", "item", "database_lock", "entity", "entity_map", "material_map", "blockdata_map", "session", "sign", "skull", "user", "username_log", "version", "world")); ConfigHandler.databaseTables.addAll(DATABASE_TABLES);
if (mySQL) { if (mySQL) {
createMySQLTables(prefix, forceConnection, purge);
}
else {
createSQLiteTables(prefix, forceConnection, purge);
}
}
private static void createMySQLTables(String prefix, Connection forceConnection, boolean purge) {
boolean success = false; boolean success = false;
try (Connection connection = (forceConnection != null ? forceConnection : Database.getConnection(true, true, true, 0))) { try (Connection connection = (forceConnection != null ? forceConnection : Database.getConnection(true, true, true, 0))) {
if (connection != null) { if (connection != null) {
String index = "";
Statement statement = connection.createStatement(); Statement statement = connection.createStatement();
index = ", INDEX(id)"; createMySQLTableStructures(prefix, statement);
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "art_map(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),id int,art varchar(255)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
index = ", INDEX(wid,x,z,time), INDEX(user,time), INDEX(type,time)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "block(rowid bigint NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid), time int, user int, wid int, x int, y int, z int, type int, data int, meta mediumblob, blockdata blob, action tinyint, rolled_back tinyint" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
index = ", INDEX(time), INDEX(user,time), INDEX(wid,x,z,time)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "chat(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),time int, user int, wid int, x int, y int (3), z int, message varchar(16000)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
index = ", INDEX(time), INDEX(user,time), INDEX(wid,x,z,time)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "command(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),time int, user int, wid int, x int, y int (3), z int, message varchar(16000)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
index = ", INDEX(wid,x,z,time), INDEX(user,time), INDEX(type,time)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "container(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid), time int, user int, wid int, x int, y int, z int, type int, data int, amount int, metadata blob, action tinyint, rolled_back tinyint" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
index = ", INDEX(wid,x,z,time), INDEX(user,time), INDEX(type,time)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "item(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid), time int, user int, wid int, x int, y int, z int, type int, data blob, amount int, action tinyint, rolled_back tinyint" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "database_lock(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),status tinyint,time int) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "entity(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid), time int, data blob) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
index = ", INDEX(id)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "entity_map(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),id int,entity varchar(255)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
index = ", INDEX(id)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "material_map(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),id int,material varchar(255)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
index = ", INDEX(id)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "blockdata_map(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),id int,data varchar(255)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
index = ", INDEX(wid,x,z,time), INDEX(action,time), INDEX(user,time), INDEX(time)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "session(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),time int, user int, wid int, x int, y int (3), z int, action tinyint" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
index = ", INDEX(wid,x,z,time), INDEX(user,time), INDEX(time)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "sign(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),time int, user int, wid int, x int, y int, z int, action tinyint, color int, color_secondary int, data tinyint, waxed tinyint, face tinyint, line_1 varchar(100), line_2 varchar(100), line_3 varchar(100), line_4 varchar(100), line_5 varchar(100), line_6 varchar(100), line_7 varchar(100), line_8 varchar(100)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "skull(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid), time int, owner varchar(255), skin varchar(255)) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
index = ", INDEX(user), INDEX(uuid)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "user(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),time int,user varchar(100),uuid varchar(64)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
index = ", INDEX(uuid,user)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "username_log(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),time int,uuid varchar(64),user varchar(100)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "version(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),time int,version varchar(16)) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
index = ", INDEX(id)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "world(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),id int,world varchar(255)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
if (!purge && forceConnection == null) { if (!purge && forceConnection == null) {
initializeTables(prefix, statement); initializeTables(prefix, statement);
} }
@ -395,7 +340,80 @@ public class Database extends Queue {
Config.getGlobal().MYSQL = false; Config.getGlobal().MYSQL = false;
} }
} }
if (!mySQL) {
private static void createMySQLTableStructures(String prefix, Statement statement) throws SQLException {
String index = "";
// Art map
index = ", INDEX(id)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "art_map(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),id int,art varchar(255)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
// Block
index = ", INDEX(wid,x,z,time), INDEX(user,time), INDEX(type,time)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "block(rowid bigint NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid), time int, user int, wid int, x int, y int, z int, type int, data int, meta mediumblob, blockdata blob, action tinyint, rolled_back tinyint" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
// Chat
index = ", INDEX(time), INDEX(user,time), INDEX(wid,x,z,time)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "chat(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),time int, user int, wid int, x int, y int (3), z int, message varchar(16000)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
// Command
index = ", INDEX(time), INDEX(user,time), INDEX(wid,x,z,time)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "command(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),time int, user int, wid int, x int, y int (3), z int, message varchar(16000)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
// Container
index = ", INDEX(wid,x,z,time), INDEX(user,time), INDEX(type,time)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "container(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid), time int, user int, wid int, x int, y int, z int, type int, data int, amount int, metadata blob, action tinyint, rolled_back tinyint" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
// Item
index = ", INDEX(wid,x,z,time), INDEX(user,time), INDEX(type,time)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "item(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid), time int, user int, wid int, x int, y int, z int, type int, data blob, amount int, action tinyint, rolled_back tinyint" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
// Database lock
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "database_lock(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),status tinyint,time int) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
// Entity
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "entity(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid), time int, data blob) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
// Entity map
index = ", INDEX(id)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "entity_map(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),id int,entity varchar(255)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
// Material map
index = ", INDEX(id)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "material_map(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),id int,material varchar(255)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
// Blockdata map
index = ", INDEX(id)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "blockdata_map(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),id int,data varchar(255)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
// Session
index = ", INDEX(wid,x,z,time), INDEX(action,time), INDEX(user,time), INDEX(time)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "session(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),time int, user int, wid int, x int, y int (3), z int, action tinyint" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
// Sign
index = ", INDEX(wid,x,z,time), INDEX(user,time), INDEX(time)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "sign(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),time int, user int, wid int, x int, y int, z int, action tinyint, color int, color_secondary int, data tinyint, waxed tinyint, face tinyint, line_1 varchar(100), line_2 varchar(100), line_3 varchar(100), line_4 varchar(100), line_5 varchar(100), line_6 varchar(100), line_7 varchar(100), line_8 varchar(100)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
// Skull
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "skull(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid), time int, owner varchar(255), skin varchar(255)) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
// User
index = ", INDEX(user), INDEX(uuid)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "user(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),time int,user varchar(100),uuid varchar(64)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
// Username log
index = ", INDEX(uuid,user)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "username_log(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),time int,uuid varchar(64),user varchar(100)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
// Version
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "version(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),time int,version varchar(16)) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
// World
index = ", INDEX(id)";
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "world(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),id int,world varchar(255)" + index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
}
private static void createSQLiteTables(String prefix, Connection forceConnection, boolean purge) {
try (Connection connection = (forceConnection != null ? forceConnection : Database.getConnection(true, 0))) { try (Connection connection = (forceConnection != null ? forceConnection : Database.getConnection(true, 0))) {
Statement statement = connection.createStatement(); Statement statement = connection.createStatement();
List<String> tableData = new ArrayList<>(); List<String> tableData = new ArrayList<>();
@ -410,6 +428,21 @@ public class Database extends Queue {
attachDatabase = "tmp_db."; attachDatabase = "tmp_db.";
} }
identifyExistingTablesAndIndexes(statement, attachDatabase, tableData, indexData);
createSQLiteTableStructures(prefix, statement, tableData);
createSQLiteIndexes(prefix, statement, indexData, attachDatabase, purge);
if (!purge && forceConnection == null) {
initializeTables(prefix, statement);
}
statement.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
private static void identifyExistingTablesAndIndexes(Statement statement, String attachDatabase, List<String> tableData, List<String> indexData) throws SQLException {
String query = "SELECT type,name FROM " + attachDatabase + "sqlite_master WHERE type='table' OR type='index';"; String query = "SELECT type,name FROM " + attachDatabase + "sqlite_master WHERE type='table' OR type='index';";
ResultSet rs = statement.executeQuery(query); ResultSet rs = statement.executeQuery(query);
while (rs.next()) { while (rs.next()) {
@ -422,7 +455,9 @@ public class Database extends Queue {
} }
} }
rs.close(); rs.close();
}
private static void createSQLiteTableStructures(String prefix, Statement statement, List<String> tableData) throws SQLException {
if (!tableData.contains(prefix + "art_map")) { if (!tableData.contains(prefix + "art_map")) {
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "art_map (id INTEGER, art TEXT);"); statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "art_map (id INTEGER, art TEXT);");
} }
@ -477,97 +512,40 @@ public class Database extends Queue {
if (!tableData.contains(prefix + "world")) { if (!tableData.contains(prefix + "world")) {
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "world (id INTEGER, world TEXT);"); statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix + "world (id INTEGER, world TEXT);");
} }
}
private static void createSQLiteIndexes(String prefix, Statement statement, List<String> indexData, String attachDatabase, boolean purge) {
try { try {
if (!indexData.contains("art_map_id_index")) { createSQLiteIndex(statement, indexData, attachDatabase, "art_map_id_index", prefix + "art_map(id)");
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "art_map_id_index ON " + ConfigHandler.prefix + "art_map(id);"); createSQLiteIndex(statement, indexData, attachDatabase, "block_index", prefix + "block(wid,x,z,time)");
} createSQLiteIndex(statement, indexData, attachDatabase, "block_user_index", prefix + "block(user,time)");
if (!indexData.contains("block_index")) { createSQLiteIndex(statement, indexData, attachDatabase, "block_type_index", prefix + "block(type,time)");
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "block_index ON " + ConfigHandler.prefix + "block(wid,x,z,time);"); createSQLiteIndex(statement, indexData, attachDatabase, "blockdata_map_id_index", prefix + "blockdata_map(id)");
} createSQLiteIndex(statement, indexData, attachDatabase, "chat_index", prefix + "chat(time)");
if (!indexData.contains("block_user_index")) { createSQLiteIndex(statement, indexData, attachDatabase, "chat_user_index", prefix + "chat(user,time)");
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "block_user_index ON " + ConfigHandler.prefix + "block(user,time);"); createSQLiteIndex(statement, indexData, attachDatabase, "chat_wid_index", prefix + "chat(wid,x,z,time)");
} createSQLiteIndex(statement, indexData, attachDatabase, "command_index", prefix + "command(time)");
if (!indexData.contains("block_type_index")) { createSQLiteIndex(statement, indexData, attachDatabase, "command_user_index", prefix + "command(user,time)");
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "block_type_index ON " + ConfigHandler.prefix + "block(type,time);"); createSQLiteIndex(statement, indexData, attachDatabase, "command_wid_index", prefix + "command(wid,x,z,time)");
} createSQLiteIndex(statement, indexData, attachDatabase, "container_index", prefix + "container(wid,x,z,time)");
if (!indexData.contains("blockdata_map_id_index")) { createSQLiteIndex(statement, indexData, attachDatabase, "container_user_index", prefix + "container(user,time)");
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "blockdata_map_id_index ON " + ConfigHandler.prefix + "blockdata_map(id);"); createSQLiteIndex(statement, indexData, attachDatabase, "container_type_index", prefix + "container(type,time)");
} createSQLiteIndex(statement, indexData, attachDatabase, "item_index", prefix + "item(wid,x,z,time)");
if (!indexData.contains("chat_index")) { createSQLiteIndex(statement, indexData, attachDatabase, "item_user_index", prefix + "item(user,time)");
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "chat_index ON " + ConfigHandler.prefix + "chat(time);"); createSQLiteIndex(statement, indexData, attachDatabase, "item_type_index", prefix + "item(type,time)");
} createSQLiteIndex(statement, indexData, attachDatabase, "entity_map_id_index", prefix + "entity_map(id)");
if (!indexData.contains("chat_user_index")) { createSQLiteIndex(statement, indexData, attachDatabase, "material_map_id_index", prefix + "material_map(id)");
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "chat_user_index ON " + ConfigHandler.prefix + "chat(user,time);"); createSQLiteIndex(statement, indexData, attachDatabase, "session_index", prefix + "session(wid,x,z,time)");
} createSQLiteIndex(statement, indexData, attachDatabase, "session_action_index", prefix + "session(action,time)");
if (!indexData.contains("chat_wid_index")) { createSQLiteIndex(statement, indexData, attachDatabase, "session_user_index", prefix + "session(user,time)");
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "chat_wid_index ON " + ConfigHandler.prefix + "chat(wid,x,z,time);"); createSQLiteIndex(statement, indexData, attachDatabase, "session_time_index", prefix + "session(time)");
} createSQLiteIndex(statement, indexData, attachDatabase, "sign_index", prefix + "sign(wid,x,z,time)");
if (!indexData.contains("command_index")) { createSQLiteIndex(statement, indexData, attachDatabase, "sign_user_index", prefix + "sign(user,time)");
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "command_index ON " + ConfigHandler.prefix + "command(time);"); createSQLiteIndex(statement, indexData, attachDatabase, "sign_time_index", prefix + "sign(time)");
} createSQLiteIndex(statement, indexData, attachDatabase, "user_index", prefix + "user(user)");
if (!indexData.contains("command_user_index")) { createSQLiteIndex(statement, indexData, attachDatabase, "uuid_index", prefix + "user(uuid)");
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "command_user_index ON " + ConfigHandler.prefix + "command(user,time);"); createSQLiteIndex(statement, indexData, attachDatabase, "username_log_uuid_index", prefix + "username_log(uuid,user)");
} createSQLiteIndex(statement, indexData, attachDatabase, "world_id_index", prefix + "world(id)");
if (!indexData.contains("command_wid_index")) {
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "command_wid_index ON " + ConfigHandler.prefix + "command(wid,x,z,time);");
}
if (!indexData.contains("container_index")) {
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "container_index ON " + ConfigHandler.prefix + "container(wid,x,z,time);");
}
if (!indexData.contains("container_user_index")) {
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "container_user_index ON " + ConfigHandler.prefix + "container(user,time);");
}
if (!indexData.contains("container_type_index")) {
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "container_type_index ON " + ConfigHandler.prefix + "container(type,time);");
}
if (!indexData.contains("item_index")) {
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "item_index ON " + ConfigHandler.prefix + "item(wid,x,z,time);");
}
if (!indexData.contains("item_user_index")) {
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "item_user_index ON " + ConfigHandler.prefix + "item(user,time);");
}
if (!indexData.contains("item_type_index")) {
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "item_type_index ON " + ConfigHandler.prefix + "item(type,time);");
}
if (!indexData.contains("entity_map_id_index")) {
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "entity_map_id_index ON " + ConfigHandler.prefix + "entity_map(id);");
}
if (!indexData.contains("material_map_id_index")) {
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "material_map_id_index ON " + ConfigHandler.prefix + "material_map(id);");
}
if (!indexData.contains("session_index")) {
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "session_index ON " + ConfigHandler.prefix + "session(wid,x,z,time);");
}
if (!indexData.contains("session_action_index")) {
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "session_action_index ON " + ConfigHandler.prefix + "session(action,time);");
}
if (!indexData.contains("session_user_index")) {
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "session_user_index ON " + ConfigHandler.prefix + "session(user,time);");
}
if (!indexData.contains("session_time_index")) {
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "session_time_index ON " + ConfigHandler.prefix + "session(time);");
}
if (!indexData.contains("sign_index")) {
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "sign_index ON " + ConfigHandler.prefix + "sign(wid,x,z,time);");
}
if (!indexData.contains("sign_user_index")) {
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "sign_user_index ON " + ConfigHandler.prefix + "sign(user,time);");
}
if (!indexData.contains("sign_time_index")) {
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "sign_time_index ON " + ConfigHandler.prefix + "sign(time);");
}
if (!indexData.contains("user_index")) {
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "user_index ON " + ConfigHandler.prefix + "user(user);");
}
if (!indexData.contains("uuid_index")) {
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "uuid_index ON " + ConfigHandler.prefix + "user(uuid);");
}
if (!indexData.contains("username_log_uuid_index")) {
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "username_log_uuid_index ON " + ConfigHandler.prefix + "username_log(uuid,user);");
}
if (!indexData.contains("world_id_index")) {
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + "world_id_index ON " + ConfigHandler.prefix + "world(id);");
}
} }
catch (Exception e) { catch (Exception e) {
Chat.console(Phrase.build(Phrase.DATABASE_INDEX_ERROR)); Chat.console(Phrase.build(Phrase.DATABASE_INDEX_ERROR));
@ -575,14 +553,11 @@ public class Database extends Queue {
e.printStackTrace(); e.printStackTrace();
} }
} }
if (!purge && forceConnection == null) {
initializeTables(prefix, statement);
}
statement.close();
}
catch (Exception e) {
e.printStackTrace();
} }
private static void createSQLiteIndex(Statement statement, List<String> indexData, String attachDatabase, String indexName, String indexColumns) throws SQLException {
if (!indexData.contains(indexName)) {
statement.executeUpdate("CREATE INDEX IF NOT EXISTS " + attachDatabase + indexName + " ON " + indexColumns + ";");
} }
} }

View file

@ -34,37 +34,31 @@ public final class WorldEditBlockState implements BlockState {
@Override @Override
public void setMetadata(String metadataKey, MetadataValue newMetadataValue) { public void setMetadata(String metadataKey, MetadataValue newMetadataValue) {
// TODO Auto-generated method stub
} }
@Override @Override
public List<MetadataValue> getMetadata(String metadataKey) { public List<MetadataValue> getMetadata(String metadataKey) {
// TODO Auto-generated method stub
return null; return null;
} }
@Override @Override
public boolean hasMetadata(String metadataKey) { public boolean hasMetadata(String metadataKey) {
// TODO Auto-generated method stub
return false; return false;
} }
@Override @Override
public void removeMetadata(String metadataKey, Plugin owningPlugin) { public void removeMetadata(String metadataKey, Plugin owningPlugin) {
// TODO Auto-generated method stub
} }
@Override @Override
public Block getBlock() { public Block getBlock() {
// TODO Auto-generated method stub
return null; return null;
} }
@Override @Override
public MaterialData getData() { public MaterialData getData() {
// TODO Auto-generated method stub
return null; return null;
} }
@ -80,7 +74,6 @@ public final class WorldEditBlockState implements BlockState {
@Override @Override
public byte getLightLevel() { public byte getLightLevel() {
// TODO Auto-generated method stub
return 0; return 0;
} }
@ -125,13 +118,11 @@ public final class WorldEditBlockState implements BlockState {
@Override @Override
public Chunk getChunk() { public Chunk getChunk() {
// TODO Auto-generated method stub
return null; return null;
} }
@Override @Override
public void setData(MaterialData data) { public void setData(MaterialData data) {
// TODO Auto-generated method stub
} }
@ -147,73 +138,61 @@ public final class WorldEditBlockState implements BlockState {
@Override @Override
public boolean update() { public boolean update() {
// TODO Auto-generated method stub
return false; return false;
} }
@Override @Override
public boolean update(boolean force) { public boolean update(boolean force) {
// TODO Auto-generated method stub
return false; return false;
} }
@Override @Override
public boolean update(boolean force, boolean applyPhysics) { public boolean update(boolean force, boolean applyPhysics) {
// TODO Auto-generated method stub
return false; return false;
} }
@Override @Override
public byte getRawData() { public byte getRawData() {
// TODO Auto-generated method stub
return 0; return 0;
} }
@Override @Override
public void setRawData(byte data) { public void setRawData(byte data) {
// TODO Auto-generated method stub
} }
@Override @Override
public boolean isPlaced() { public boolean isPlaced() {
// TODO Auto-generated method stub
return false; return false;
} }
@Override @Override
public boolean isCollidable() { public boolean isCollidable() {
// TODO Auto-generated method stub
return false; return false;
} }
@Override @Override
public Collection<ItemStack> getDrops() { public Collection<ItemStack> getDrops() {
// TODO Auto-generated method stub
return null; return null;
} }
@Override @Override
public Collection<ItemStack> getDrops(ItemStack tool) { public Collection<ItemStack> getDrops(ItemStack tool) {
// TODO Auto-generated method stub
return null; return null;
} }
@Override @Override
public Collection<ItemStack> getDrops(ItemStack tool, Entity entity) { public Collection<ItemStack> getDrops(ItemStack tool, Entity entity) {
// TODO Auto-generated method stub
return null; return null;
} }
@Override @Override
public BlockState copy() { public BlockState copy() {
// TODO Auto-generated method stub
return null; return null;
} }
@Override @Override
public BlockState copy(Location location) { public BlockState copy(Location location) {
// TODO Auto-generated method stub
return null; return null;
} }