Added SQL support, CMI support & tab completing.

This commit is contained in:
Lilac 2019-08-06 19:48:28 +01:00
parent e289af886a
commit e3ac861143
28 changed files with 856 additions and 49 deletions

View File

@ -4,7 +4,7 @@ stages:
variables:
name: "UltimateKits"
path: "/builds/$CI_PROJECT_PATH"
version: "2.3.19"
version: "2.3.20"
build:
stage: build

16
pom.xml
View File

@ -55,6 +55,7 @@
<artifactSet>
<includes>
<include>com.songoda:songodaupdater</include>
<include>com.zaxxer:HikariCP</include>
</includes>
</artifactSet>
<filters>
@ -221,5 +222,20 @@
<version>0.1.3.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.zrips</groupId>
<artifactId>CMI</artifactId>
<version>8.0.8.1</version>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.23.1</version>
</dependency>
</dependencies>
</project>

View File

@ -2,6 +2,11 @@ package com.songoda.ultimatekits;
import com.songoda.ultimatekits.command.CommandManager;
import com.songoda.ultimatekits.conversion.Convert;
import com.songoda.ultimatekits.database.DataManager;
import com.songoda.ultimatekits.database.DataMigrationManager;
import com.songoda.ultimatekits.database.DatabaseConnector;
import com.songoda.ultimatekits.database.MySQLConnector;
import com.songoda.ultimatekits.database.SQLiteConnector;
import com.songoda.ultimatekits.economy.Economy;
import com.songoda.ultimatekits.economy.PlayerPointsEconomy;
import com.songoda.ultimatekits.economy.ReserveEconomy;
@ -59,6 +64,10 @@ public class UltimateKits extends JavaPlugin {
private ItemSerializer itemSerializer;
private DatabaseConnector databaseConnector;
private DataMigrationManager dataMigrationManager;
private DataManager dataManager;
/**
* Grab instance of UltimateKits
*
@ -136,8 +145,38 @@ public class UltimateKits extends JavaPlugin {
// Starting Metrics
new Metrics(this);
console.sendMessage(Methods.formatText("&a============================="));
try {
if (Setting.MYSQL_ENABLED.getBoolean()) {
String hostname = Setting.MYSQL_HOSTNAME.getString();
int port = Setting.MYSQL_PORT.getInt();
String database = Setting.MYSQL_DATABASE.getString();
String username = Setting.MYSQL_USERNAME.getString();
String password = Setting.MYSQL_PASSWORD.getString();
boolean useSSL = Setting.MYSQL_USE_SSL.getBoolean();
this.databaseConnector = new MySQLConnector(this, hostname, port, database, username, password, useSSL);
this.getLogger().info("Data handler connected using MySQL.");
} else {
this.databaseConnector = new SQLiteConnector(this);
this.getLogger().info("Data handler connected using SQLite.");
}
} catch (Exception ex) {
this.getLogger().severe("Fatal error trying to connect to database. " +
"Please make sure all your connection settings are correct and try again. Plugin has been disabled.");
Bukkit.getPluginManager().disablePlugin(this);
}
this.dataManager = new DataManager(this.databaseConnector, this);
this.dataMigrationManager = new DataMigrationManager(this.databaseConnector, this.dataManager);
this.dataMigrationManager.runMigrations();
Bukkit.getScheduler().runTaskLater(this, () -> {
this.dataManager.getBlockData((blockData) -> {
this.kitManager.setKitLocations(blockData);
});
}, 20L);
console.sendMessage(Methods.formatText("&a============================="));
}
/*
@ -146,6 +185,7 @@ public class UltimateKits extends JavaPlugin {
public void onDisable() {
saveToFile();
kitManager.clearKits();
this.dataManager.bulkUpdateBlockData(this.getKitManager().getKitLocations());
console.sendMessage(Methods.formatText("&a============================="));
console.sendMessage(Methods.formatText("&7UltimateKits " + this.getDescription().getVersion() + " by &5Songoda <3!"));
console.sendMessage(Methods.formatText("&7Action: &cDisabling&7..."));
@ -273,26 +313,8 @@ public class UltimateKits extends JavaPlugin {
kitFile.getConfig().set("Kits." + kit.getName() + ".items", strContents);
}
// Wipe old block information.
dataFile.getConfig().set("BlockData", null);
/*
* Save kit locations from KitManager to Configuration.
*/
for (KitBlockData kitBlockData : kitManager.getKitLocations().values()) {
String locationStr = Methods.serializeLocation(kitBlockData.getLocation());
if (locationStr == null) continue;
dataFile.getConfig().set("BlockData." + locationStr + ".type", kitBlockData.getType().name());
dataFile.getConfig().set("BlockData." + locationStr + ".kit", kitBlockData.getKit().getName());
dataFile.getConfig().set("BlockData." + locationStr + ".holograms", kitBlockData.showHologram());
dataFile.getConfig().set("BlockData." + locationStr + ".displayItems", kitBlockData.isDisplayingItems());
dataFile.getConfig().set("BlockData." + locationStr + ".particles", kitBlockData.hasParticles());
dataFile.getConfig().set("BlockData." + locationStr + ".itemOverride", kitBlockData.isItemOverride());
}
// Save to file
kitFile.saveConfig();
dataFile.saveConfig();
}
/*
@ -391,4 +413,12 @@ public class UltimateKits extends JavaPlugin {
public DisplayItemHandler getDisplayItemHandler() {
return displayItemHandler;
}
public DatabaseConnector getDatabaseConnector() {
return databaseConnector;
}
public DataManager getDataManager() {
return dataManager;
}
}

View File

@ -3,18 +3,34 @@ package com.songoda.ultimatekits.command;
import com.songoda.ultimatekits.UltimateKits;
import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public abstract class AbstractCommand {
private final AbstractCommand parent;
private final String command;
private final boolean noConsole;
private final boolean subCommands;
private AbstractCommand parent = null;
private boolean hasArgs = false;
private String command;
protected AbstractCommand(String command, AbstractCommand parent, boolean noConsole, boolean subCommands) {
this.command = command;
private List<String> subCommand = new ArrayList<>();
protected AbstractCommand(AbstractCommand parent, boolean noConsole, String... command) {
if (parent != null) {
this.subCommand = Arrays.asList(command);
} else {
this.command = Arrays.asList(command).get(0);
}
this.parent = parent;
this.noConsole = noConsole;
this.subCommands = subCommands;
}
protected AbstractCommand(boolean noConsole, boolean hasArgs, String... command) {
this.command = Arrays.asList(command).get(0);
this.hasArgs = hasArgs;
this.noConsole = noConsole;
}
public AbstractCommand getParent() {
@ -25,21 +41,32 @@ public abstract class AbstractCommand {
return command;
}
public boolean isNoConsole() {
return noConsole;
public List<String> getSubCommand() {
return subCommand;
}
public boolean isSubCommands() {
return subCommands;
public void addSubCommand(String command) {
subCommand.add(command);
}
protected abstract ReturnType runCommand(UltimateKits instance, CommandSender sender, String... args);
protected abstract List<String> onTab(UltimateKits instance, CommandSender sender, String... args);
public abstract String getPermissionNode();
public abstract String getSyntax();
public abstract String getDescription();
public boolean hasArgs() {
return hasArgs;
}
public boolean isNoConsole() {
return noConsole;
}
public enum ReturnType {SUCCESS, FAILURE, SYNTAX_ERROR}
}

View File

@ -15,11 +15,13 @@ import java.util.List;
public class CommandManager implements CommandExecutor {
private UltimateKits plugin;
private TabManager tabManager;
private List<AbstractCommand> commands = new ArrayList<>();
public CommandManager(UltimateKits plugin) {
this.plugin = plugin;
this.tabManager = new TabManager(this);
plugin.getCommand("kitadmin").setExecutor(this);
plugin.getCommand("kit").setExecutor(this);
@ -36,6 +38,11 @@ public class CommandManager implements CommandExecutor {
addCommand(new CommandKey(commandUltimateKits));
addCommand(new CommandSet(commandUltimateKits));
addCommand(new CommandRemove(commandUltimateKits));
for (AbstractCommand abstractCommand : commands) {
if (abstractCommand.getParent() != null) continue;
plugin.getCommand(abstractCommand.getCommand()).setTabCompleter(tabManager);
}
}
private AbstractCommand addCommand(AbstractCommand abstractCommand) {
@ -46,16 +53,19 @@ public class CommandManager implements CommandExecutor {
@Override
public boolean onCommand(CommandSender commandSender, Command command, String s, String[] strings) {
for (AbstractCommand abstractCommand : commands) {
if (abstractCommand.getCommand().equalsIgnoreCase(command.getName())) {
if (strings.length == 0 || !abstractCommand.isSubCommands()) {
if (abstractCommand.getCommand() != null && abstractCommand.getCommand().equalsIgnoreCase(command.getName().toLowerCase())) {
if (strings.length == 0 || abstractCommand.hasArgs()) {
processRequirements(abstractCommand, commandSender, strings);
return true;
}
} else if (strings.length != 0 && abstractCommand.getParent() != null && abstractCommand.getParent().getCommand().equalsIgnoreCase(command.getName())) {
String cmd = strings[0];
if (cmd.equalsIgnoreCase(abstractCommand.getCommand())) {
processRequirements(abstractCommand, commandSender, strings);
return true;
String cmd2 = strings.length >= 2 ? String.join(" ", strings[0], strings[1]) : null;
for (String cmds : abstractCommand.getSubCommand()) {
if (cmd.equalsIgnoreCase(cmds) || (cmd2 != null && cmd2.equalsIgnoreCase(cmds))) {
processRequirements(abstractCommand, commandSender, strings);
return true;
}
}
}
}
@ -76,7 +86,7 @@ public class CommandManager implements CommandExecutor {
}
return;
}
plugin.getLocale().newMessage("event.general.nopermission").sendPrefixedMessage(sender);
plugin.getLocale().getMessage("event.general.nopermission").sendPrefixedMessage(sender);
}
public List<AbstractCommand> getCommands() {

View File

@ -0,0 +1,52 @@
package com.songoda.ultimatekits.command;
import com.songoda.ultimatekits.UltimateKits;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import java.util.ArrayList;
import java.util.List;
public class TabManager implements TabCompleter {
private final CommandManager commandManager;
TabManager(CommandManager commandManager) {
this.commandManager = commandManager;
}
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] strings) {
for (AbstractCommand abstractCommand : commandManager.getCommands()) {
if (abstractCommand.getCommand() != null && abstractCommand.getCommand().equalsIgnoreCase(command.getName().toLowerCase())) {
if (strings.length == 1) {
List<String> subs = new ArrayList<>();
for (AbstractCommand ac : commandManager.getCommands()) {
if (ac.getSubCommand() == null) continue;
subs.addAll(ac.getSubCommand());
}
subs.removeIf(s -> !s.toLowerCase().startsWith(strings[0].toLowerCase()));
return subs;
}
} else if (strings.length != 0 && abstractCommand.getParent() != null && abstractCommand.getParent().getCommand().equalsIgnoreCase(command.getName().toLowerCase())) {
String cmd = strings[0];
String cmd2 = strings.length >= 2 ? String.join(" ", strings[0], strings[1]) : null;
for (String cmds : abstractCommand.getSubCommand()) {
if (cmd.equalsIgnoreCase(cmds) || (cmd2 != null && cmd2.equalsIgnoreCase(cmds))) {
List<String> list = abstractCommand.onTab(UltimateKits.getInstance(), sender, strings);
String str = strings[strings.length - 1];
if (list != null && str != null && str.length() >= 1) {
try {
list.removeIf(s -> !s.toLowerCase().startsWith(str.toLowerCase()));
} catch (UnsupportedOperationException ignored) {
}
}
return list;
}
}
}
}
return new ArrayList<>();
}
}

View File

@ -8,10 +8,14 @@ import com.songoda.ultimatekits.utils.Methods;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class CommandCreatekit extends AbstractCommand {
public CommandCreatekit(AbstractCommand parent) {
super("createkit", parent, true, false);
super(parent, true, "createkit");
}
@Override
@ -31,6 +35,11 @@ public class CommandCreatekit extends AbstractCommand {
return ReturnType.SUCCESS;
}
@Override
protected List<String> onTab(UltimateKits instance, CommandSender sender, String... args) {
return Arrays.asList("name");
}
@Override
public String getPermissionNode() {
return "ultimatekits.admin";

View File

@ -1,19 +1,25 @@
package com.songoda.ultimatekits.command.commands;
import bammerbom.ultimatecore.bukkit.UltimateMetrics;
import com.songoda.ultimatekits.UltimateKits;
import com.songoda.ultimatekits.command.AbstractCommand;
import com.songoda.ultimatekits.gui.GUIBlockEditor;
import com.songoda.ultimatekits.gui.GUIKitEditor;
import com.songoda.ultimatekits.kit.Kit;
import com.songoda.ultimatekits.kit.KitBlockData;
import com.songoda.ultimatekits.kit.KitManager;
import com.songoda.ultimatekits.utils.Methods;
import org.bukkit.block.Block;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class CommandEdit extends AbstractCommand {
public CommandEdit(AbstractCommand parent) {
super("edit", parent, true, false);
super(parent, true, "edit");
}
@Override
@ -41,6 +47,19 @@ public class CommandEdit extends AbstractCommand {
return ReturnType.SUCCESS;
}
@Override
protected List<String> onTab(UltimateKits instance, CommandSender sender, String... args) {
if (!(sender instanceof Player)) return null;
List<String> tab = new ArrayList<>();
if (args.length == 2) {
for (Kit kit : UltimateKits.getInstance().getKitManager().getKits())
tab.add(kit.getName());
return tab;
}
return tab;
}
@Override
public String getPermissionNode() {
return "ultimatekits.admin";

View File

@ -9,10 +9,14 @@ import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class CommandKey extends AbstractCommand {
public CommandKey(AbstractCommand parent) {
super("key", parent, false, false);
super(parent, false, "key");
}
@Override
@ -66,6 +70,36 @@ public class CommandKey extends AbstractCommand {
return ReturnType.SUCCESS;
}
@Override
protected List<String> onTab(UltimateKits instance, CommandSender sender, String... args) {
if (!(sender instanceof Player)) return null;
List<String> tab = new ArrayList<>();
if (args.length == 2) {
tab.add("all");
for (Kit kit : UltimateKits.getInstance().getKitManager().getKits())
tab.add(kit.getName());
return tab;
}
if (args.length == 3) {
for (Key key : UltimateKits.getInstance().getKeyManager().getKeys())
tab.add(key.getName());
return tab;
}
if (args.length == 4) {
tab.add("all");
for (Player player : Bukkit.getOnlinePlayers())
tab.add(player.getName());
return tab;
}
if (args.length == 5) return Arrays.asList("amount");
return tab;
}
@Override
public String getPermissionNode() {
return "ultimatekits.admin";

View File

@ -9,10 +9,13 @@ import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class CommandKit extends AbstractCommand {
public CommandKit() {
super("Kit", null, false, false);
super(null, false, "kit");
}
@Override
@ -72,6 +75,11 @@ public class CommandKit extends AbstractCommand {
return ReturnType.SYNTAX_ERROR;
}
@Override
protected List<String> onTab(UltimateKits instance, CommandSender sender, String... args) {
return new ArrayList<>();
}
@Override
public String getPermissionNode() {
return null;

View File

@ -6,10 +6,13 @@ import com.songoda.ultimatekits.kit.Kit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class CommandPreviewKit extends AbstractCommand {
public CommandPreviewKit() {
super("PreviewKit", null, true, false);
super(null, true, "PreviewKit");
}
@Override
@ -28,6 +31,19 @@ public class CommandPreviewKit extends AbstractCommand {
return ReturnType.SUCCESS;
}
@Override
protected List<String> onTab(UltimateKits instance, CommandSender sender, String... args) {
if (!(sender instanceof Player)) return null;
if (args.length == 2) {
List<String> tab = new ArrayList<>();
for (Kit kit : UltimateKits.getInstance().getKitManager().getKits())
tab.add(kit.getName());
return tab;
}
return new ArrayList<>();
}
@Override
public String getPermissionNode() {
return null;

View File

@ -5,10 +5,13 @@ import com.songoda.ultimatekits.command.AbstractCommand;
import com.songoda.ultimatekits.utils.Methods;
import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.List;
public class CommandReload extends AbstractCommand {
public CommandReload(AbstractCommand parent) {
super("reload", parent, false, false);
super(parent, false, "reload");
}
@Override
@ -18,6 +21,11 @@ public class CommandReload extends AbstractCommand {
return ReturnType.SUCCESS;
}
@Override
protected List<String> onTab(UltimateKits instance, CommandSender sender, String... args) {
return new ArrayList<>();
}
@Override
public String getPermissionNode() {
return "ultimatekits.admin";

View File

@ -7,10 +7,13 @@ import org.bukkit.block.Block;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class CommandRemove extends AbstractCommand {
public CommandRemove(AbstractCommand parent) {
super("remove", parent, true, false);
super(parent, true, "remove");
}
@Override
@ -30,6 +33,11 @@ public class CommandRemove extends AbstractCommand {
return ReturnType.SUCCESS;
}
@Override
protected List<String> onTab(UltimateKits instance, CommandSender sender, String... args) {
return new ArrayList<>();
}
@Override
public String getPermissionNode() {
return "ultimatekits.admin";

View File

@ -2,15 +2,19 @@ package com.songoda.ultimatekits.command.commands;
import com.songoda.ultimatekits.UltimateKits;
import com.songoda.ultimatekits.command.AbstractCommand;
import com.songoda.ultimatekits.kit.Kit;
import com.songoda.ultimatekits.utils.Methods;
import org.bukkit.block.Block;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class CommandSet extends AbstractCommand {
public CommandSet(AbstractCommand parent) {
super("set", parent, true, false);
super(parent, true, "set");
}
@Override
@ -32,6 +36,19 @@ public class CommandSet extends AbstractCommand {
return ReturnType.SUCCESS;
}
@Override
protected List<String> onTab(UltimateKits instance, CommandSender sender, String... args) {
if (!(sender instanceof Player)) return null;
if (args.length == 2) {
List<String> tab = new ArrayList<>();
for (Kit kit : UltimateKits.getInstance().getKitManager().getKits())
tab.add(kit.getName());
return tab;
}
return new ArrayList<>();
}
@Override
public String getPermissionNode() {
return "ultimatekits.admin";

View File

@ -5,10 +5,13 @@ import com.songoda.ultimatekits.command.AbstractCommand;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class CommandSettings extends AbstractCommand {
public CommandSettings(AbstractCommand parent) {
super("settings", parent, true, false);
super(parent, true, "settings");
}
@Override
@ -17,6 +20,11 @@ public class CommandSettings extends AbstractCommand {
return ReturnType.SUCCESS;
}
@Override
protected List<String> onTab(UltimateKits instance, CommandSender sender, String... args) {
return new ArrayList<>();
}
@Override
public String getPermissionNode() {
return "ultimatekits.admin";

View File

@ -5,10 +5,13 @@ import com.songoda.ultimatekits.command.AbstractCommand;
import com.songoda.ultimatekits.utils.Methods;
import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.List;
public class CommandUltimateKits extends AbstractCommand {
public CommandUltimateKits() {
super("KitAdmin", null, false, true);
super(null, false, "KitAdmin");
}
@Override
@ -27,6 +30,11 @@ public class CommandUltimateKits extends AbstractCommand {
return ReturnType.SUCCESS;
}
@Override
protected List<String> onTab(UltimateKits instance, CommandSender sender, String... args) {
return new ArrayList<>();
}
@Override
public String getPermissionNode() {
return null;

View File

@ -1,6 +1,7 @@
package com.songoda.ultimatekits.conversion;
import com.songoda.ultimatekits.UltimateKits;
import com.songoda.ultimatekits.conversion.hooks.CMIHook;
import com.songoda.ultimatekits.conversion.hooks.DefaultHook;
import com.songoda.ultimatekits.conversion.hooks.EssentialsHook;
import com.songoda.ultimatekits.conversion.hooks.UltimateCoreHook;
@ -27,6 +28,9 @@ public class Convert {
}
} else if (instance.getServer().getPluginManager().getPlugin("UltimateCore") != null) {
hook = new UltimateCoreHook();
} else if (instance.getServer().getPluginManager().getPlugin("CMI") != null) {
hook = new CMIHook();
} else {
hook = new DefaultHook();
}

View File

@ -0,0 +1,43 @@
package com.songoda.ultimatekits.conversion.hooks;
import com.Zrips.CMI.CMI;
import com.Zrips.CMI.Modules.Kits.Kit;
import com.songoda.ultimatekits.UltimateKits;
import com.songoda.ultimatekits.conversion.Hook;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.inventory.ItemStack;
import java.util.HashSet;
import java.util.Set;
public class CMIHook implements Hook {
private CMI cmi;
public CMIHook() {
cmi = (CMI) UltimateKits.getInstance().getServer().getPluginManager().getPlugin("CMI");
}
public Set<ItemStack> getItems(String kitName) {
Set<ItemStack> stacks = new HashSet<>();
try {
Kit kit = cmi.getKitsManager().getKit(kitName, true);
for (ItemStack item : kit.getItems()) {
if (item != null) stacks.add(item);
}
} catch (Exception e) {
e.printStackTrace();
}
return stacks;
}
public Set<String> getKits() {
return cmi.getKitsManager().getKitMap().keySet();
}
public long getDelay(String kitName) {
return cmi.getKitsManager().getKit(kitName, true).getDelay();
}
}

View File

@ -0,0 +1,166 @@
package com.songoda.ultimatekits.database;
import com.songoda.ultimatekits.UltimateKits;
import com.songoda.ultimatekits.kit.KitBlockData;
import com.songoda.ultimatekits.kit.KitType;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.plugin.Plugin;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
public class DataManager {
private final DatabaseConnector databaseConnector;
private final Plugin plugin;
public DataManager(DatabaseConnector databaseConnector, Plugin plugin) {
this.databaseConnector = databaseConnector;
this.plugin = plugin;
}
public String getTablePrefix() {
return this.plugin.getDescription().getName().toLowerCase() + '_';
}
public void bulkUpdateBlockData(Map<Location, KitBlockData> blockData) {
this.databaseConnector.connect(connection -> {
String updateData = "UPDATE " + this.getTablePrefix() + "blockdata SET kit = ? WHERE " +
"world = ? AND x = ? AND y = ? AND z = ?";
try (PreparedStatement statement = connection.prepareStatement(updateData)) {
for (int i = 0; i < blockData.size(); i++) {
KitBlockData data = blockData.get(i);
statement.setString(2, data.getKit().getName());
statement.setString(7, data.getWorld().getName());
statement.setInt(8, data.getX());
statement.setInt(9, data.getY());
statement.setInt(10, data.getZ());
statement.executeUpdate();
statement.addBatch();
}
statement.executeBatch();
}
});
}
public void updateBlockData(KitBlockData blockData) {
this.async(() -> this.databaseConnector.connect(connection -> {
String updateData = "UPDATE " + this.getTablePrefix() + "blockdata SET kit = ? WHERE " +
"world = ? AND x = ? AND y = ? AND z = ?";
try (PreparedStatement statement = connection.prepareStatement(updateData)) {
statement.setString(2, blockData.getKit().getName());
statement.setString(7, blockData.getWorld().getName());
statement.setInt(8, blockData.getX());
statement.setInt(9, blockData.getY());
statement.setInt(10, blockData.getZ());
statement.executeUpdate();
}
}));
}
public void createBlockData(KitBlockData blockData) {
this.async(() -> this.databaseConnector.connect(connection -> {
String createData ="INSERT INTO " + this.getTablePrefix() + "blockdata (" +
"type, kit, holograms, displayItems, particles, itemOverride, world, x, y, z)" +
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
try (PreparedStatement statement = connection.prepareStatement(createData)) {
statement.setString(1, blockData.getType().toString());
statement.setString(2, blockData.getKit().getName());
statement.setBoolean(3, blockData.showHologram());
statement.setBoolean(4, blockData.isDisplayingItems());
statement.setBoolean(5, blockData.hasParticles());
statement.setBoolean(6, blockData.isItemOverride());
statement.setString(7, blockData.getWorld().getName());
statement.setInt(8, blockData.getX());
statement.setInt(9, blockData.getY());
statement.setInt(10, blockData.getZ());
statement.executeUpdate();
}
}));
}
public void deleteBlockData(KitBlockData blockData) {
this.async(() -> this.databaseConnector.connect(connection -> {
String deleteData = "DELETE FROM " + this.getTablePrefix() + "blockdata WHERE world = ? " +
"AND x = ? AND y = ? AND z = ?";
try (PreparedStatement statement = connection.prepareStatement(deleteData)) {
statement.setString(1, blockData.getType().toString());
statement.setString(2, blockData.getKit().getName());
statement.setBoolean(3, blockData.showHologram());
statement.setBoolean(4, blockData.isDisplayingItems());
statement.setBoolean(5, blockData.hasParticles());
statement.setBoolean(6, blockData.isItemOverride());
statement.setString(7, blockData.getWorld().getName());
statement.setInt(8, blockData.getX());
statement.setInt(9, blockData.getY());
statement.setInt(10, blockData.getZ());
statement.executeUpdate();
}
}));
}
public void getBlockData(Consumer<Map<Location, KitBlockData>> callback) {
this.async(() -> this.databaseConnector.connect(connection -> {
String selectData = "SELECT * FROM " + this.getTablePrefix() + "blockdata";
Map<Location, KitBlockData> blockData = new HashMap<>();
try (Statement statement = connection.createStatement()) {
ResultSet result = statement.executeQuery(selectData);
while (result.next()) {
KitType type = KitType.valueOf(result.getString("type"));
String kit = result.getString("kit");
boolean holograms = result.getBoolean("holograms");
boolean displayItems = result.getBoolean("displayItems");
boolean particles = result.getBoolean("particles");
boolean itemOverride = result.getBoolean("itemOverride");
World world = Bukkit.getWorld(result.getString("world"));
int x = result.getInt("x");
int y = result.getInt("y");
int z = result.getInt("z");
Location location = new Location(world, x, y, z);
KitBlockData kitBlockData =
new KitBlockData(UltimateKits.getInstance().getKitManager().getKit(kit),
location, type, holograms, particles, displayItems, itemOverride);
blockData.put(location, kitBlockData);
}
}
this.sync(() -> callback.accept(blockData));
}));
}
private int lastInsertedId(Connection connection) {
String query;
if (this.databaseConnector instanceof SQLiteConnector) {
query = "SELECT last_insert_rowid()";
} else {
query = "SELECT LAST_INSERT_ID()";
}
try (Statement statement = connection.createStatement()) {
ResultSet result = statement.executeQuery(query);
result.next();
return result.getInt(1);
} catch (SQLException e) {
e.printStackTrace();
return -1;
}
}
public void async(Runnable runnable) {
Bukkit.getScheduler().runTaskAsynchronously(this.plugin, runnable);
}
public void sync(Runnable runnable) {
Bukkit.getScheduler().runTask(this.plugin, runnable);
}
}

View File

@ -0,0 +1,19 @@
package com.songoda.ultimatekits.database;
import java.sql.Connection;
import java.sql.SQLException;
public abstract class DataMigration {
private final int revision;
public DataMigration(int revision) {
this.revision = revision;
}
public abstract void migrate(Connection connection, String tablePrefix) throws SQLException;
public int getRevision() {
return this.revision;
}
}

View File

@ -0,0 +1,108 @@
package com.songoda.ultimatekits.database;
import com.songoda.ultimatekits.database.migrations._1_InitialMigration;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
public class DataMigrationManager {
private List<DataMigration> migrations;
private DatabaseConnector databaseConnector;
private DataManager dataManager;
public DataMigrationManager(DatabaseConnector databaseConnector, DataManager dataManager) {
this.databaseConnector = databaseConnector;
this.dataManager = dataManager;
this.migrations = Arrays.asList(
new _1_InitialMigration()
);
}
/**
* Runs any needed data migrations
*/
public void runMigrations() {
this.databaseConnector.connect((connection -> {
int currentMigration = -1;
boolean migrationsExist;
String query;
if (this.databaseConnector instanceof SQLiteConnector) {
query = "SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?";
} else {
query = "SHOW TABLES LIKE ?";
}
try (PreparedStatement statement = connection.prepareStatement(query)) {
statement.setString(1, this.getMigrationsTableName());
migrationsExist = statement.executeQuery().next();
}
if (!migrationsExist) {
// No migration table exists, create one
String createTable = "CREATE TABLE " + this.getMigrationsTableName() + " (migration_version INT NOT NULL)";
try (PreparedStatement statement = connection.prepareStatement(createTable)) {
statement.execute();
}
// Insert primary row into migration table
String insertRow = "INSERT INTO " + this.getMigrationsTableName() + " VALUES (?)";
try (PreparedStatement statement = connection.prepareStatement(insertRow)) {
statement.setInt(1, -1);
statement.execute();
}
} else {
// Grab the current migration version
String selectVersion = "SELECT migration_version FROM " + this.getMigrationsTableName();
try (PreparedStatement statement = connection.prepareStatement(selectVersion)) {
ResultSet result = statement.executeQuery();
result.next();
currentMigration = result.getInt("migration_version");
}
}
// Grab required migrations
int finalCurrentMigration = currentMigration;
List<DataMigration> requiredMigrations = this.migrations
.stream()
.filter(x -> x.getRevision() > finalCurrentMigration)
.sorted(Comparator.comparingInt(DataMigration::getRevision))
.collect(Collectors.toList());
// Nothing to migrate, abort
if (requiredMigrations.isEmpty())
return;
// Migrate the data
for (DataMigration dataMigration : requiredMigrations)
dataMigration.migrate(connection, this.dataManager.getTablePrefix());
// Set the new current migration to be the highest migrated to
currentMigration = requiredMigrations
.stream()
.map(DataMigration::getRevision)
.max(Integer::compareTo)
.orElse(-1);
String updateVersion = "UPDATE " + this.getMigrationsTableName() + " SET migration_version = ?";
try (PreparedStatement statement = connection.prepareStatement(updateVersion)) {
statement.setInt(1, currentMigration);
statement.execute();
}
}));
}
/**
* @return the name of the migrations table
*/
private String getMigrationsTableName() {
return this.dataManager.getTablePrefix() + "migrations";
}
}

View File

@ -0,0 +1,34 @@
package com.songoda.ultimatekits.database;
import java.sql.Connection;
import java.sql.SQLException;
public interface DatabaseConnector {
/**
* Checks if the connection to the database has been created
*
* @return true if the connection is created, otherwise false
*/
boolean isInitialized();
/**
* Closes all open connections to the database
*/
void closeConnection();
/**
* Executes a callback with a Connection passed and automatically closes it when finished
*
* @param callback The callback to execute once the connection is retrieved
*/
void connect(ConnectionCallback callback);
/**
* Wraps a connection in a callback which will automagically handle catching sql errors
*/
interface ConnectionCallback {
void accept(Connection connection) throws SQLException;
}
}

View File

@ -0,0 +1,49 @@
package com.songoda.ultimatekits.database;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.bukkit.plugin.Plugin;
import java.sql.Connection;
import java.sql.SQLException;
public class MySQLConnector implements DatabaseConnector {
private final Plugin plugin;
private HikariDataSource hikari;
private boolean initializedSuccessfully;
public MySQLConnector(Plugin plugin, String hostname, int port, String database, String username, String password, boolean useSSL) {
this.plugin = plugin;
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://" + hostname + ":" + port + "/" + database + "?useSSL=" + useSSL);
config.setUsername(username);
config.setPassword(password);
config.setMaximumPoolSize(3);
try {
this.hikari = new HikariDataSource(config);
this.initializedSuccessfully = true;
} catch (Exception ex) {
this.initializedSuccessfully = false;
}
}
public boolean isInitialized() {
return this.initializedSuccessfully;
}
public void closeConnection() {
this.hikari.close();
}
public void connect(ConnectionCallback callback) {
try (Connection connection = this.hikari.getConnection()) {
callback.accept(connection);
} catch (SQLException ex) {
this.plugin.getLogger().severe("An error occurred executing a MySQL query: " + ex.getMessage());
ex.printStackTrace();
}
}
}

View File

@ -0,0 +1,58 @@
package com.songoda.ultimatekits.database;
import org.bukkit.plugin.Plugin;
import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class SQLiteConnector implements DatabaseConnector {
private final Plugin plugin;
private final String connectionString;
private Connection connection;
public SQLiteConnector(Plugin plugin) {
this.plugin = plugin;
this.connectionString = "jdbc:sqlite:" + plugin.getDataFolder() + File.separator + plugin.getDescription().getName().toLowerCase() + ".db";
try {
Class.forName("org.sqlite.JDBC"); // This is required to put here for Spigot 1.10 and below for some reason
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public boolean isInitialized() {
return true; // Always available
}
public void closeConnection() {
try {
if (this.connection != null) {
this.connection.close();
}
} catch (SQLException ex) {
this.plugin.getLogger().severe("An error occurred closing the SQLite database connection: " + ex.getMessage());
}
}
public void connect(ConnectionCallback callback) {
if (this.connection == null) {
try {
this.connection = DriverManager.getConnection(this.connectionString);
} catch (SQLException ex) {
this.plugin.getLogger().severe("An error occurred retrieving the SQLite database connection: " + ex.getMessage());
}
}
try {
callback.accept(this.connection);
} catch (Exception ex) {
this.plugin.getLogger().severe("An error occurred executing an SQLite query: " + ex.getMessage());
ex.printStackTrace();
}
}
}

View File

@ -0,0 +1,38 @@
package com.songoda.ultimatekits.database.migrations;
import com.songoda.ultimatekits.UltimateKits;
import com.songoda.ultimatekits.database.DataMigration;
import com.songoda.ultimatekits.database.MySQLConnector;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
public class _1_InitialMigration extends DataMigration {
public _1_InitialMigration() {
super(1);
}
@Override
public void migrate(Connection connection, String tablePrefix) throws SQLException {
String autoIncrement = UltimateKits.getInstance().getDatabaseConnector() instanceof
MySQLConnector ? " AUTO_INCREMENT" : "";
// Create plugin settings table
try (Statement statement = connection.createStatement()) {
statement.execute("CREATE TABLE " + tablePrefix + "blockdata (" +
"type TEXT NOT NULL," +
"kit TEXT NOT NULL," +
"holograms BOOLEAN NOT NULL," +
"displayItems BOOLEAN NOT NULL," +
"particles BOOLEAN NOT NULL," +
"itemOverride BOOLEAN NOT NULL," +
"world TEXT NOT NULL," +
"x INTEGER NOT NULL," +
"y INTEGER NOT NULL," +
"z INTEGER NOT NULL " +
")");
}
}
}

View File

@ -7,7 +7,7 @@ import java.util.*;
public final class KitManager {
private final Map<Location, KitBlockData> kitsAtLocations = new HashMap<>();
private Map<Location, KitBlockData> kitsAtLocations = new HashMap<>();
private List<Kit> registeredKits = new LinkedList<>();
public boolean addKit(Kit kit) {
@ -30,13 +30,16 @@ public final class KitManager {
}
public void addKitToLocation(Kit kit, Location location) {
kitsAtLocations.put(roundLocation(location), new KitBlockData(kit, location));
KitBlockData data = new KitBlockData(kit, location);
kitsAtLocations.put(roundLocation(location), data);
UltimateKits.getInstance().getDataManager().createBlockData(data);
}
public void addKitToLocation(Kit kit, Location location, KitType type, boolean hologram, boolean particles, boolean items, boolean itemOverride) {
KitBlockData kitBlockData = kitsAtLocations.put(roundLocation(location), new KitBlockData(kit, location, type, hologram, particles, items, itemOverride));
if (UltimateKits.getInstance().getHologram() != null)
UltimateKits.getInstance().getHologram().update(kitBlockData);
UltimateKits.getInstance().getDataManager().createBlockData(kitBlockData);
}
public Kit removeKitFromLocation(Location location) {
@ -47,6 +50,7 @@ public final class KitManager {
kit.reset();
KitBlockData removed = kitsAtLocations.remove(roundLocation(location));
UltimateKits.getInstance().getDataManager().deleteBlockData(removed);
return (removed != null ? removed.getKit() : null);
}
@ -68,6 +72,10 @@ public final class KitManager {
return Collections.unmodifiableMap(kitsAtLocations);
}
public void setKitLocations(Map<Location, KitBlockData> kits) {
kitsAtLocations = kits;
}
public void clearKits() {
this.registeredKits.clear();
this.kitsAtLocations.clear();

View File

@ -39,7 +39,15 @@ public enum Setting {
LANGUGE_MODE("System.Language Mode", "en_US",
"The enabled language file.",
"More language files (if available) can be found in the plugins data folder.");
"More language files (if available) can be found in the plugins data folder."),
MYSQL_ENABLED("MySQL.Enabled", false, "Set to 'true' to use MySQL for data storage."),
MYSQL_HOSTNAME("MySQL.Hostname", "localhost"),
MYSQL_PORT("MySQL.Port", 3306),
MYSQL_DATABASE("MySQL.Database", "your-database"),
MYSQL_USERNAME("MySQL.Username", "user"),
MYSQL_PASSWORD("MySQL.Password", "pass"),
MYSQL_USE_SSL("MySQL.Use SSL", false);
private String setting;
private Object option;

View File

@ -11,6 +11,7 @@ import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
@ -35,6 +36,7 @@ public class SettingsManager implements Listener {
@EventHandler
public void onInventoryClick(InventoryClickEvent event) {
if (event.getView().getType() != InventoryType.CHEST) return;
ItemStack clickedItem = event.getCurrentItem();
if (event.getInventory() != event.getWhoClicked().getOpenInventory().getTopInventory()