mirror of
https://github.com/PikaMug/Quests.git
synced 2025-02-12 18:41:22 +01:00
Add optional MySQL implementation, part 1. See #312
This commit is contained in:
parent
6d5d3deff6
commit
ce9b24fe3a
@ -13,7 +13,6 @@
|
||||
package me.blackvein.quests;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
@ -36,7 +35,6 @@ import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.conversations.Conversable;
|
||||
@ -61,6 +59,7 @@ import me.blackvein.quests.events.quest.QuestTakeEvent;
|
||||
import me.blackvein.quests.events.quester.QuesterPostStartQuestEvent;
|
||||
import me.blackvein.quests.events.quester.QuesterPreOpenGUIEvent;
|
||||
import me.blackvein.quests.events.quester.QuesterPreStartQuestEvent;
|
||||
import me.blackvein.quests.storage.Storage;
|
||||
import me.blackvein.quests.tasks.StageTimer;
|
||||
import me.blackvein.quests.util.ConfigUtil;
|
||||
import me.blackvein.quests.util.InventoryUtil;
|
||||
@ -2833,14 +2832,13 @@ public class Quester implements Comparable<Quester> {
|
||||
* @return true if successful
|
||||
*/
|
||||
public boolean saveData() {
|
||||
final FileConfiguration data = getBaseData();
|
||||
try {
|
||||
data.save(new File(plugin.getDataFolder(), "data" + File.separator + id + ".yml"));
|
||||
return true;
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
final Storage storage = plugin.getStorage();
|
||||
storage.saveQuesterData(this);
|
||||
} catch (final Exception e) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3200,7 +3198,7 @@ public class Quester implements Comparable<Quester> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether data file for this Quester exists
|
||||
* Get data file for this Quester
|
||||
*
|
||||
* @return file if exists, otherwise null
|
||||
*/
|
||||
@ -3221,386 +3219,8 @@ public class Quester implements Comparable<Quester> {
|
||||
*
|
||||
* @return true if successful
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public boolean loadData() {
|
||||
final FileConfiguration data = new YamlConfiguration();
|
||||
try {
|
||||
final File dataFile = getDataFile();
|
||||
if (dataFile != null) {
|
||||
data.load(dataFile);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
return false;
|
||||
} catch (final InvalidConfigurationException e) {
|
||||
return false;
|
||||
}
|
||||
hardClear();
|
||||
if (data.contains("completedRedoableQuests")) {
|
||||
final List<String> redoNames = data.getStringList("completedRedoableQuests");
|
||||
final List<Long> redoTimes = data.getLongList("completedQuestTimes");
|
||||
for (final String s : redoNames) {
|
||||
for (final Quest q : plugin.getQuests()) {
|
||||
if (q.getName().equalsIgnoreCase(s)) {
|
||||
completedTimes.put(q.getName(), redoTimes.get(redoNames.indexOf(s)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data.contains("amountsCompletedQuests")) {
|
||||
final List<String> list1 = data.getStringList("amountsCompletedQuests");
|
||||
final List<Integer> list2 = data.getIntegerList("amountsCompleted");
|
||||
for (int i = 0; i < list1.size(); i++) {
|
||||
amountsCompleted.put(list1.get(i), list2.get(i));
|
||||
}
|
||||
}
|
||||
questPoints = data.getInt("quest-points");
|
||||
hasJournal = data.getBoolean("hasJournal");
|
||||
if (data.isList("completed-Quests")) {
|
||||
for (final String s : data.getStringList("completed-Quests")) {
|
||||
for (final Quest q : plugin.getQuests()) {
|
||||
if (q.getName().equalsIgnoreCase(s)) {
|
||||
if (!completedQuests.contains(q.getName())) {
|
||||
completedQuests.add(q.getName());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
completedQuests.clear();
|
||||
}
|
||||
if (data.isString("currentQuests") == false) {
|
||||
final List<String> questNames = data.getStringList("currentQuests");
|
||||
final List<Integer> questStages = data.getIntegerList("currentStages");
|
||||
// These appear to differ sometimes? That seems bad.
|
||||
final int maxSize = Math.min(questNames.size(), questStages.size());
|
||||
for (int i = 0; i < maxSize; i++) {
|
||||
if (plugin.getQuest(questNames.get(i)) != null) {
|
||||
currentQuests.put(plugin.getQuest(questNames.get(i)), questStages.get(i));
|
||||
}
|
||||
}
|
||||
final ConfigurationSection dataSec = data.getConfigurationSection("questData");
|
||||
if (dataSec == null || dataSec.getKeys(false).isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
for (final String key : dataSec.getKeys(false)) {
|
||||
final ConfigurationSection questSec = dataSec.getConfigurationSection(key);
|
||||
final Quest quest = plugin.getQuest(key);
|
||||
Stage stage;
|
||||
if (quest == null || currentQuests.containsKey(quest) == false) {
|
||||
continue;
|
||||
}
|
||||
stage = getCurrentStage(quest);
|
||||
if (stage == null) {
|
||||
quest.completeQuest(this);
|
||||
plugin.getLogger().severe("[Quests] Invalid stage number for player: \"" + id + "\" on Quest \""
|
||||
+ quest.getName() + "\". Quest ended.");
|
||||
continue;
|
||||
}
|
||||
addEmptiesFor(quest, currentQuests.get(quest));
|
||||
if (questSec == null)
|
||||
continue;
|
||||
if (questSec.contains("blocks-broken-names")) {
|
||||
final List<String> names = questSec.getStringList("blocks-broken-names");
|
||||
final List<Integer> amounts = questSec.getIntegerList("blocks-broken-amounts");
|
||||
final List<Short> durability = questSec.getShortList("blocks-broken-durability");
|
||||
int index = 0;
|
||||
for (final String s : names) {
|
||||
ItemStack is;
|
||||
try {
|
||||
is = new ItemStack(Material.matchMaterial(s), amounts.get(index), durability.get(index));
|
||||
} catch (final IndexOutOfBoundsException e) {
|
||||
// Legacy
|
||||
is = new ItemStack(Material.matchMaterial(s), amounts.get(index), (short) 0);
|
||||
}
|
||||
if (getQuestData(quest).blocksBroken.size() > 0) {
|
||||
getQuestData(quest).blocksBroken.set(index, is);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
if (questSec.contains("blocks-damaged-names")) {
|
||||
final List<String> names = questSec.getStringList("blocks-damaged-names");
|
||||
final List<Integer> amounts = questSec.getIntegerList("blocks-damaged-amounts");
|
||||
final List<Short> durability = questSec.getShortList("blocks-damaged-durability");
|
||||
int index = 0;
|
||||
for (final String s : names) {
|
||||
ItemStack is;
|
||||
try {
|
||||
is = new ItemStack(Material.matchMaterial(s), amounts.get(index), durability.get(index));
|
||||
} catch (final IndexOutOfBoundsException e) {
|
||||
// Legacy
|
||||
is = new ItemStack(Material.matchMaterial(s), amounts.get(index), (short) 0);
|
||||
}
|
||||
if (getQuestData(quest).blocksDamaged.size() > 0) {
|
||||
getQuestData(quest).blocksDamaged.set(index, is);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
if (questSec.contains("blocks-placed-names")) {
|
||||
final List<String> names = questSec.getStringList("blocks-placed-names");
|
||||
final List<Integer> amounts = questSec.getIntegerList("blocks-placed-amounts");
|
||||
final List<Short> durability = questSec.getShortList("blocks-placed-durability");
|
||||
int index = 0;
|
||||
for (final String s : names) {
|
||||
ItemStack is;
|
||||
try {
|
||||
is = new ItemStack(Material.matchMaterial(s), amounts.get(index), durability.get(index));
|
||||
} catch (final IndexOutOfBoundsException e) {
|
||||
// Legacy
|
||||
is = new ItemStack(Material.matchMaterial(s), amounts.get(index), (short) 0);
|
||||
}
|
||||
if (getQuestData(quest).blocksPlaced.size() > 0) {
|
||||
getQuestData(quest).blocksPlaced.set(index, is);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
if (questSec.contains("blocks-used-names")) {
|
||||
final List<String> names = questSec.getStringList("blocks-used-names");
|
||||
final List<Integer> amounts = questSec.getIntegerList("blocks-used-amounts");
|
||||
final List<Short> durability = questSec.getShortList("blocks-used-durability");
|
||||
int index = 0;
|
||||
for (final String s : names) {
|
||||
ItemStack is;
|
||||
try {
|
||||
is = new ItemStack(Material.matchMaterial(s), amounts.get(index), durability.get(index));
|
||||
} catch (final IndexOutOfBoundsException e) {
|
||||
// Legacy
|
||||
is = new ItemStack(Material.matchMaterial(s), amounts.get(index), (short) 0);
|
||||
}
|
||||
if (getQuestData(quest).blocksUsed.size() > 0) {
|
||||
getQuestData(quest).blocksUsed.set(index, is);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
if (questSec.contains("blocks-cut-names")) {
|
||||
final List<String> names = questSec.getStringList("blocks-cut-names");
|
||||
final List<Integer> amounts = questSec.getIntegerList("blocks-cut-amounts");
|
||||
final List<Short> durability = questSec.getShortList("blocks-cut-durability");
|
||||
int index = 0;
|
||||
for (final String s : names) {
|
||||
ItemStack is;
|
||||
try {
|
||||
is = new ItemStack(Material.matchMaterial(s), amounts.get(index), durability.get(index));
|
||||
} catch (final IndexOutOfBoundsException e) {
|
||||
// Legacy
|
||||
is = new ItemStack(Material.matchMaterial(s), amounts.get(index), (short) 0);
|
||||
}
|
||||
if (getQuestData(quest).blocksCut.size() > 0) {
|
||||
getQuestData(quest).blocksCut.set(index, is);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
if (questSec.contains("item-craft-amounts")) {
|
||||
final List<Integer> craftAmounts = questSec.getIntegerList("item-craft-amounts");
|
||||
for (int i = 0; i < craftAmounts.size(); i++) {
|
||||
if (i < getCurrentStage(quest).itemsToCraft.size()) {
|
||||
getQuestData(quest).itemsCrafted.put(getCurrentStage(quest).itemsToCraft
|
||||
.get(i), craftAmounts.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (questSec.contains("item-smelt-amounts")) {
|
||||
final List<Integer> smeltAmounts = questSec.getIntegerList("item-smelt-amounts");
|
||||
for (int i = 0; i < smeltAmounts.size(); i++) {
|
||||
if (i < getCurrentStage(quest).itemsToSmelt.size()) {
|
||||
getQuestData(quest).itemsSmelted.put(getCurrentStage(quest).itemsToSmelt
|
||||
.get(i), smeltAmounts.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (questSec.contains("item-enchant-amounts")) {
|
||||
final List<Integer> enchantAmounts = questSec.getIntegerList("item-enchant-amounts");
|
||||
for (int i = 0; i < enchantAmounts.size(); i++) {
|
||||
if (i < getCurrentStage(quest).itemsToEnchant.size()) {
|
||||
getQuestData(quest).itemsEnchanted.put(getCurrentStage(quest).itemsToEnchant
|
||||
.get(i), enchantAmounts.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (questSec.contains("item-brew-amounts")) {
|
||||
final List<Integer> brewAmounts = questSec.getIntegerList("item-brew-amounts");
|
||||
for (int i = 0; i < brewAmounts.size(); i++) {
|
||||
if (i < getCurrentStage(quest).itemsToBrew.size()) {
|
||||
getQuestData(quest).itemsBrewed.put(getCurrentStage(quest).itemsToBrew
|
||||
.get(i), brewAmounts.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (questSec.contains("item-consume-amounts")) {
|
||||
final List<Integer> consumeAmounts = questSec.getIntegerList("item-consume-amounts");
|
||||
for (int i = 0; i < consumeAmounts.size(); i++) {
|
||||
if (i < getCurrentStage(quest).itemsToConsume.size()) {
|
||||
getQuestData(quest).itemsConsumed.put(getCurrentStage(quest).itemsToConsume
|
||||
.get(i), consumeAmounts.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (questSec.contains("cows-milked")) {
|
||||
getQuestData(quest).setCowsMilked(questSec.getInt("cows-milked"));
|
||||
}
|
||||
if (questSec.contains("fish-caught")) {
|
||||
getQuestData(quest).setFishCaught(questSec.getInt("fish-caught"));
|
||||
}
|
||||
if (questSec.contains("players-killed")) {
|
||||
getQuestData(quest).setPlayersKilled(questSec.getInt("players-killed"));
|
||||
}
|
||||
if (questSec.contains("mobs-killed")) {
|
||||
final LinkedList<EntityType> mobs = new LinkedList<EntityType>();
|
||||
final List<Integer> amounts = questSec.getIntegerList("mobs-killed-amounts");
|
||||
for (final String s : questSec.getStringList("mobs-killed")) {
|
||||
final EntityType mob = MiscUtil.getProperMobType(s);
|
||||
if (mob != null) {
|
||||
mobs.add(mob);
|
||||
}
|
||||
getQuestData(quest).mobsKilled.clear();
|
||||
getQuestData(quest).mobNumKilled.clear();
|
||||
for (final EntityType e : mobs) {
|
||||
getQuestData(quest).mobsKilled.add(e);
|
||||
getQuestData(quest).mobNumKilled.add(amounts.get(mobs.indexOf(e)));
|
||||
}
|
||||
if (questSec.contains("mob-kill-locations")) {
|
||||
final LinkedList<Location> locations = new LinkedList<Location>();
|
||||
final List<Integer> radii = questSec.getIntegerList("mob-kill-location-radii");
|
||||
for (final String loc : questSec.getStringList("mob-kill-locations")) {
|
||||
if (ConfigUtil.getLocation(loc) != null) {
|
||||
locations.add(ConfigUtil.getLocation(loc));
|
||||
}
|
||||
}
|
||||
getQuestData(quest).locationsToKillWithin = locations;
|
||||
getQuestData(quest).radiiToKillWithin.clear();
|
||||
for (final int i : radii) {
|
||||
getQuestData(quest).radiiToKillWithin.add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (questSec.contains("item-delivery-amounts")) {
|
||||
final List<Integer> deliveryAmounts = questSec.getIntegerList("item-delivery-amounts");
|
||||
int index = 0;
|
||||
for (final int amt : deliveryAmounts) {
|
||||
final ItemStack is = getCurrentStage(quest).itemsToDeliver.get(index);
|
||||
final ItemStack temp = new ItemStack(is.getType(), amt, is.getDurability());
|
||||
try {
|
||||
temp.addEnchantments(is.getEnchantments());
|
||||
} catch (final Exception e) {
|
||||
plugin.getLogger().warning("Unable to add enchantment(s) " + is.getEnchantments().toString()
|
||||
+ " to delivery item " + is.getType().name() + " x " + amt + " for quest "
|
||||
+ quest.getName());
|
||||
}
|
||||
temp.setItemMeta(is.getItemMeta());
|
||||
if (getQuestData(quest).itemsDelivered.size() > 0) {
|
||||
getQuestData(quest).itemsDelivered.set(index, temp);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
if (questSec.contains("citizen-ids-to-talk-to")) {
|
||||
final List<Integer> ids = questSec.getIntegerList("citizen-ids-to-talk-to");
|
||||
final List<Boolean> has = questSec.getBooleanList("has-talked-to");
|
||||
for (final int i : ids) {
|
||||
getQuestData(quest).citizensInteracted.put(i, has.get(ids.indexOf(i)));
|
||||
}
|
||||
}
|
||||
if (questSec.contains("citizen-ids-killed")) {
|
||||
final List<Integer> ids = questSec.getIntegerList("citizen-ids-killed");
|
||||
final List<Integer> num = questSec.getIntegerList("citizen-amounts-killed");
|
||||
getQuestData(quest).citizensKilled.clear();
|
||||
getQuestData(quest).citizenNumKilled.clear();
|
||||
for (final int i : ids) {
|
||||
getQuestData(quest).citizensKilled.add(i);
|
||||
getQuestData(quest).citizenNumKilled.add(num.get(ids.indexOf(i)));
|
||||
}
|
||||
}
|
||||
if (questSec.contains("locations-to-reach")) {
|
||||
final LinkedList<Location> locations = new LinkedList<Location>();
|
||||
final List<Boolean> has = questSec.getBooleanList("has-reached-location");
|
||||
while (has.size() < locations.size()) {
|
||||
// TODO - Find proper cause of Github issues #646 and #825
|
||||
plugin.getLogger().info("Added missing has-reached-location data for Quester " + id);
|
||||
has.add(false);
|
||||
}
|
||||
final List<Integer> radii = questSec.getIntegerList("radii-to-reach-within");
|
||||
for (final String loc : questSec.getStringList("locations-to-reach")) {
|
||||
if (ConfigUtil.getLocation(loc) != null) {
|
||||
locations.add(ConfigUtil.getLocation(loc));
|
||||
}
|
||||
}
|
||||
getQuestData(quest).locationsReached = locations;
|
||||
getQuestData(quest).hasReached.clear();
|
||||
getQuestData(quest).radiiToReachWithin.clear();
|
||||
for (final boolean b : has) {
|
||||
getQuestData(quest).hasReached.add(b);
|
||||
}
|
||||
for (final int i : radii) {
|
||||
getQuestData(quest).radiiToReachWithin.add(i);
|
||||
}
|
||||
}
|
||||
if (questSec.contains("mobs-to-tame")) {
|
||||
final List<String> mobs = questSec.getStringList("mobs-to-tame");
|
||||
final List<Integer> amounts = questSec.getIntegerList("mob-tame-amounts");
|
||||
for (final String mob : mobs) {
|
||||
getQuestData(quest).mobsTamed.put(EntityType.valueOf(mob.toUpperCase()), amounts
|
||||
.get(mobs.indexOf(mob)));
|
||||
}
|
||||
}
|
||||
if (questSec.contains("sheep-to-shear")) {
|
||||
final List<String> colors = questSec.getStringList("sheep-to-shear");
|
||||
final List<Integer> amounts = questSec.getIntegerList("sheep-sheared");
|
||||
for (final String color : colors) {
|
||||
getQuestData(quest).sheepSheared.put(MiscUtil.getProperDyeColor(color), amounts.get(colors
|
||||
.indexOf(color)));
|
||||
}
|
||||
}
|
||||
if (questSec.contains("passwords")) {
|
||||
final List<String> passwords = questSec.getStringList("passwords");
|
||||
final List<Boolean> said = questSec.getBooleanList("passwords-said");
|
||||
for (int i = 0; i < passwords.size(); i++) {
|
||||
getQuestData(quest).passwordsSaid.put(passwords.get(i), said.get(i));
|
||||
}
|
||||
}
|
||||
if (questSec.contains("custom-objectives")) {
|
||||
final List<String> customObj = questSec.getStringList("custom-objectives");
|
||||
final List<Integer> customObjCount = questSec.getIntegerList("custom-objective-counts");
|
||||
for (int i = 0; i < customObj.size(); i++) {
|
||||
getQuestData(quest).customObjectiveCounts.put(customObj.get(i), customObjCount.get(i));
|
||||
}
|
||||
}
|
||||
if (questSec.contains("stage-delay")) {
|
||||
getQuestData(quest).setDelayTimeLeft(questSec.getLong("stage-delay"));
|
||||
}
|
||||
if (getCurrentStage(quest).chatActions.isEmpty() == false) {
|
||||
for (final String chatTrig : getCurrentStage(quest).chatActions.keySet()) {
|
||||
getQuestData(quest).actionFired.put(chatTrig, false);
|
||||
}
|
||||
}
|
||||
if (questSec.contains("chat-triggers")) {
|
||||
final List<String> chatTriggers = questSec.getStringList("chat-triggers");
|
||||
for (final String s : chatTriggers) {
|
||||
getQuestData(quest).actionFired.put(s, true);
|
||||
}
|
||||
}
|
||||
if (getCurrentStage(quest).commandActions.isEmpty() == false) {
|
||||
for (final String commandTrig : getCurrentStage(quest).commandActions.keySet()) {
|
||||
getQuestData(quest).actionFired.put(commandTrig, false);
|
||||
}
|
||||
}
|
||||
if (questSec.contains("command-triggers")) {
|
||||
final List<String> commandTriggers = questSec.getStringList("command-triggers");
|
||||
for (final String s : commandTriggers) {
|
||||
getQuestData(quest).actionFired.put(s, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return plugin.getStorage().loadQuesterData(id) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -95,6 +95,8 @@ import me.blackvein.quests.listeners.ItemListener;
|
||||
import me.blackvein.quests.listeners.NpcListener;
|
||||
import me.blackvein.quests.listeners.PartiesListener;
|
||||
import me.blackvein.quests.listeners.PlayerListener;
|
||||
import me.blackvein.quests.storage.Storage;
|
||||
import me.blackvein.quests.storage.StorageFactory;
|
||||
import me.blackvein.quests.tasks.NpcEffectThread;
|
||||
import me.blackvein.quests.tasks.PlayerMoveThread;
|
||||
import me.blackvein.quests.util.ConfigUtil;
|
||||
@ -136,6 +138,7 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
|
||||
private PartiesListener partiesListener;
|
||||
private DenizenTrigger trigger;
|
||||
private LocaleQuery localeQuery;
|
||||
private Storage storage;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
@ -186,6 +189,8 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
|
||||
// 7 - Save config with any new options
|
||||
getConfig().options().copyDefaults(true);
|
||||
saveConfig();
|
||||
final StorageFactory storageFactory = new StorageFactory(this);
|
||||
storage = storageFactory.getInstance();
|
||||
|
||||
// 8 - Setup commands
|
||||
getCommand("quests").setExecutor(cmdExecutor);
|
||||
@ -418,6 +423,10 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
|
||||
public LocaleQuery getLocaleQuery() {
|
||||
return localeQuery;
|
||||
}
|
||||
|
||||
public Storage getStorage() {
|
||||
return storage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void conversationAbandoned(final ConversationAbandonedEvent abandonedEvent) {
|
||||
|
@ -1380,7 +1380,7 @@ public class CmdExecutor implements CommandExecutor {
|
||||
}
|
||||
final UUID id = target.getUniqueId();
|
||||
final ConcurrentSkipListSet<Quester> temp = (ConcurrentSkipListSet<Quester>) plugin.getOfflineQuesters();
|
||||
for(final Iterator<Quester> itr = temp.iterator(); itr.hasNext();) {
|
||||
for (final Iterator<Quester> itr = temp.iterator(); itr.hasNext();) {
|
||||
if (itr.next().getUUID().equals(id)) {
|
||||
itr.remove();
|
||||
}
|
||||
|
121
main/src/main/java/me/blackvein/quests/storage/Storage.java
Normal file
121
main/src/main/java/me/blackvein/quests/storage/Storage.java
Normal file
@ -0,0 +1,121 @@
|
||||
/*******************************************************************************************************
|
||||
* Continued by PikaMug (formerly HappyPikachu) with permission from _Blackvein_. All rights reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************************************/
|
||||
|
||||
package me.blackvein.quests.storage;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
|
||||
import me.blackvein.quests.Quester;
|
||||
import me.blackvein.quests.Quests;
|
||||
import me.blackvein.quests.storage.implementation.StorageImplementation;
|
||||
|
||||
public class Storage {
|
||||
private final Quests plugin;
|
||||
private final StorageImplementation implementation;
|
||||
|
||||
public Storage(final Quests plugin, final StorageImplementation implementation) {
|
||||
this.plugin = plugin;
|
||||
this.implementation = implementation;
|
||||
}
|
||||
|
||||
public StorageImplementation getImplementation() {
|
||||
return implementation;
|
||||
}
|
||||
|
||||
public Collection<StorageImplementation> getImplementations() {
|
||||
return Collections.singleton(implementation);
|
||||
}
|
||||
|
||||
private <T> CompletableFuture<T> makeFuture(final Callable<T> supplier) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
return supplier.call();
|
||||
} catch (final Exception e) {
|
||||
if (e instanceof RuntimeException) {
|
||||
throw (RuntimeException) e;
|
||||
}
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> makeFuture(final Runnable runnable) {
|
||||
return CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
runnable.run();
|
||||
} catch (final Exception e) {
|
||||
if (e instanceof RuntimeException) {
|
||||
throw (RuntimeException) e;
|
||||
}
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return implementation.getImplementationName();
|
||||
}
|
||||
|
||||
public void init() {
|
||||
try {
|
||||
implementation.init();
|
||||
} catch (final Exception e) {
|
||||
plugin.getLogger().severe("Failed to initialize storage implementation");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
implementation.close();
|
||||
} catch (final Exception e) {
|
||||
plugin.getLogger().severe("Failed to close storage implementation");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<Quester> loadQuesterData(final UUID uniqueId) {
|
||||
return makeFuture(() -> {
|
||||
final Quester quester = implementation.loadQuesterData(uniqueId);
|
||||
return quester;
|
||||
});
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> saveQuesterData(final Quester quester) {
|
||||
return makeFuture(() -> {
|
||||
try {
|
||||
implementation.saveQuesterData(quester);
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> deletePlayerData(final UUID uniqueId) {
|
||||
return makeFuture(() -> {
|
||||
try {
|
||||
implementation.deleteQuesterData(uniqueId);
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public CompletableFuture<String> getQuesterLastKnownName(final UUID uniqueId) {
|
||||
return makeFuture(() -> implementation.getQuesterLastKnownName(uniqueId));
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/*******************************************************************************************************
|
||||
* Continued by PikaMug (formerly HappyPikachu) with permission from _Blackvein_. All rights reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************************************/
|
||||
|
||||
package me.blackvein.quests.storage;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import me.blackvein.quests.Quests;
|
||||
import me.blackvein.quests.storage.implementation.StorageImplementation;
|
||||
import me.blackvein.quests.storage.implementation.custom.CustomStorageProviders;
|
||||
import me.blackvein.quests.storage.implementation.file.SeparatedYamlStorage;
|
||||
import me.blackvein.quests.storage.implementation.sql.SqlStorage;
|
||||
import me.blackvein.quests.storage.implementation.sql.connection.hikari.MySqlConnectionFactory;
|
||||
import me.blackvein.quests.storage.misc.StorageCredentials;
|
||||
|
||||
public class StorageFactory {
|
||||
private final Quests plugin;
|
||||
|
||||
public StorageFactory(final Quests plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public Set<StorageType> getRequiredTypes() {
|
||||
return ImmutableSet.of(StorageType.parse(plugin.getConfig().getString("storage-method", "yaml"), StorageType.YAML));
|
||||
}
|
||||
|
||||
public Storage getInstance() {
|
||||
Storage storage;
|
||||
|
||||
final StorageType type = StorageType.parse(plugin.getConfig().getString("storage-method", "yaml"), StorageType.YAML);
|
||||
plugin.getLogger().info("Loading storage implementation: " + type.name());
|
||||
storage = new Storage(plugin, createNewImplementation(type));
|
||||
|
||||
storage.init();
|
||||
return storage;
|
||||
}
|
||||
|
||||
private StorageImplementation createNewImplementation(final StorageType method) {
|
||||
switch (method) {
|
||||
case CUSTOM:
|
||||
return CustomStorageProviders.getProvider().provide(plugin);
|
||||
case MYSQL:
|
||||
return new SqlStorage(
|
||||
plugin,
|
||||
new MySqlConnectionFactory(getDatabaseValues(plugin.getConfig())),
|
||||
plugin.getConfig().getString("storage-data.table_prefix")
|
||||
);
|
||||
case YAML:
|
||||
return new SeparatedYamlStorage(plugin, plugin.getDataFolder() + File.separator + "data");
|
||||
default:
|
||||
throw new RuntimeException("Unknown method: " + method);
|
||||
}
|
||||
}
|
||||
|
||||
private StorageCredentials getDatabaseValues(final FileConfiguration fc) {
|
||||
final int maxPoolSize = fc.getInt("storage-data.pool-settings.max-pool-size", fc.getInt("storage-data.pool-size", 10));
|
||||
final int minIdle = fc.getInt("storage-data.pool-settings.min-idle", maxPoolSize);
|
||||
final int maxLifetime = fc.getInt("storage-data.pool-settings.max-lifetime", 1800000);
|
||||
final int connectionTimeout = fc.getInt("storage-data.pool-settings.connection-timeout", 5000);
|
||||
|
||||
return new StorageCredentials(
|
||||
fc.getString("storage-data.address", null),
|
||||
fc.getString("storage-data.database", null),
|
||||
fc.getString("storage-data.username", null),
|
||||
fc.getString("storage-data.password", null),
|
||||
maxPoolSize, minIdle, maxLifetime, connectionTimeout, Collections.singletonMap("true", "utf8")
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*******************************************************************************************************
|
||||
* Continued by PikaMug (formerly HappyPikachu) with permission from _Blackvein_. All rights reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************************************/
|
||||
|
||||
package me.blackvein.quests.storage;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
public enum StorageType {
|
||||
|
||||
// Local file
|
||||
YAML("YAML", "yaml", "yml"),
|
||||
|
||||
// Remote database
|
||||
MYSQL("MySQL", "mysql"),
|
||||
|
||||
// Custom
|
||||
CUSTOM("Custom", "custom");
|
||||
|
||||
private final String name;
|
||||
|
||||
private final List<String> identifiers;
|
||||
|
||||
StorageType(final String name, final String... identifiers) {
|
||||
this.name = name;
|
||||
this.identifiers = ImmutableList.copyOf(identifiers);
|
||||
}
|
||||
|
||||
public static StorageType parse(final String name, final StorageType def) {
|
||||
for (final StorageType t : values()) {
|
||||
for (final String id : t.getIdentifiers()) {
|
||||
if (id.equalsIgnoreCase(name)) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<String> getIdentifiers() {
|
||||
return identifiers;
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*******************************************************************************************************
|
||||
* Continued by PikaMug (formerly HappyPikachu) with permission from _Blackvein_. All rights reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************************************/
|
||||
|
||||
package me.blackvein.quests.storage.implementation;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import me.blackvein.quests.Quester;
|
||||
import me.blackvein.quests.Quests;
|
||||
|
||||
public interface StorageImplementation {
|
||||
Quests getPlugin();
|
||||
|
||||
String getImplementationName();
|
||||
|
||||
void init() throws Exception;
|
||||
|
||||
void close();
|
||||
|
||||
Quester loadQuesterData(UUID uniqueId) throws Exception;
|
||||
|
||||
void saveQuesterData(Quester quester) throws Exception;
|
||||
|
||||
void deleteQuesterData(UUID uniqueId) throws Exception;
|
||||
|
||||
String getQuesterLastKnownName(UUID uniqueId) throws Exception;
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
/*******************************************************************************************************
|
||||
* Continued by PikaMug (formerly HappyPikachu) with permission from _Blackvein_. All rights reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************************************/
|
||||
|
||||
package me.blackvein.quests.storage.implementation.custom;
|
||||
|
||||
import me.blackvein.quests.Quests;
|
||||
import me.blackvein.quests.storage.implementation.StorageImplementation;
|
||||
|
||||
public interface CustomStorageProvider {
|
||||
StorageImplementation provide(Quests plugin);
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*******************************************************************************************************
|
||||
* Continued by PikaMug (formerly HappyPikachu) with permission from _Blackvein_. All rights reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************************************/
|
||||
|
||||
package me.blackvein.quests.storage.implementation.custom;
|
||||
|
||||
public final class CustomStorageProviders {
|
||||
private CustomStorageProviders() {}
|
||||
|
||||
private static CustomStorageProvider provider = null;
|
||||
|
||||
public static void register(final CustomStorageProvider provider) {
|
||||
CustomStorageProviders.provider = provider;
|
||||
}
|
||||
|
||||
public static CustomStorageProvider getProvider() {
|
||||
if (provider == null) {
|
||||
throw new IllegalStateException("Provider not found.");
|
||||
}
|
||||
|
||||
return provider;
|
||||
}
|
||||
}
|
@ -0,0 +1,498 @@
|
||||
/*******************************************************************************************************
|
||||
* Continued by PikaMug (formerly HappyPikachu) with permission from _Blackvein_. All rights reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************************************/
|
||||
|
||||
package me.blackvein.quests.storage.implementation.file;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import me.blackvein.quests.Quest;
|
||||
import me.blackvein.quests.Quester;
|
||||
import me.blackvein.quests.Quests;
|
||||
import me.blackvein.quests.Stage;
|
||||
import me.blackvein.quests.storage.implementation.StorageImplementation;
|
||||
import me.blackvein.quests.util.ConfigUtil;
|
||||
import me.blackvein.quests.util.MiscUtil;
|
||||
|
||||
public class SeparatedYamlStorage implements StorageImplementation {
|
||||
private final Quests plugin;
|
||||
private final String directoryPath;
|
||||
|
||||
public SeparatedYamlStorage(final Quests plugin, final String directoryPath) {
|
||||
this.plugin = plugin;
|
||||
this.directoryPath = directoryPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Quests getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getImplementationName() {
|
||||
return "YAML";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() throws Exception {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public Quester loadQuesterData(final UUID uniqueId) throws Exception {
|
||||
final FileConfiguration data = new YamlConfiguration();
|
||||
Quester quester = plugin.getQuester(uniqueId);
|
||||
if (quester != null) {
|
||||
quester.hardClear();
|
||||
} else {
|
||||
quester = new Quester(plugin, uniqueId);
|
||||
}
|
||||
try {
|
||||
final File dataFile = quester.getDataFile();
|
||||
if (dataFile != null) {
|
||||
data.load(dataFile);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} catch (final InvalidConfigurationException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
if (data.contains("completedRedoableQuests")) {
|
||||
final List<String> redoNames = data.getStringList("completedRedoableQuests");
|
||||
final List<Long> redoTimes = data.getLongList("completedQuestTimes");
|
||||
for (final String s : redoNames) {
|
||||
for (final Quest q : plugin.getQuests()) {
|
||||
if (q.getName().equalsIgnoreCase(s)) {
|
||||
final Map<String, Long> completedTimes = quester.getCompletedTimes();
|
||||
completedTimes.put(q.getName(), redoTimes.get(redoNames.indexOf(s)));
|
||||
quester.setCompletedTimes(completedTimes);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data.contains("amountsCompletedQuests")) {
|
||||
final List<String> list1 = data.getStringList("amountsCompletedQuests");
|
||||
final List<Integer> list2 = data.getIntegerList("amountsCompleted");
|
||||
for (int i = 0; i < list1.size(); i++) {
|
||||
final Map<String, Integer> amountsCompleted = quester.getAmountsCompleted();
|
||||
amountsCompleted.put(list1.get(i), list2.get(i));
|
||||
quester.setAmountsCompleted(amountsCompleted);
|
||||
}
|
||||
}
|
||||
int questPoints = quester.getQuestPoints();
|
||||
questPoints = data.getInt("quest-points");
|
||||
quester.setQuestPoints(questPoints);
|
||||
quester.hasJournal = data.getBoolean("hasJournal");
|
||||
if (data.isList("completed-Quests")) {
|
||||
for (final String s : data.getStringList("completed-Quests")) {
|
||||
for (final Quest q : plugin.getQuests()) {
|
||||
if (q.getName().equalsIgnoreCase(s)) {
|
||||
if (!quester.getCompletedQuests().contains(q.getName())) {
|
||||
final LinkedList<String> completedQuests = quester.getCompletedQuests();
|
||||
completedQuests.add(q.getName());
|
||||
quester.setCompletedQuests(completedQuests);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quester.setCompletedQuests(new LinkedList<String>());
|
||||
}
|
||||
if (data.isString("currentQuests") == false) {
|
||||
final List<String> questNames = data.getStringList("currentQuests");
|
||||
final List<Integer> questStages = data.getIntegerList("currentStages");
|
||||
// These appear to differ sometimes? That seems bad.
|
||||
final int maxSize = Math.min(questNames.size(), questStages.size());
|
||||
for (int i = 0; i < maxSize; i++) {
|
||||
if (plugin.getQuest(questNames.get(i)) != null) {
|
||||
final ConcurrentHashMap<Quest, Integer> currentQuests = quester.getCurrentQuests();
|
||||
currentQuests.put(plugin.getQuest(questNames.get(i)), questStages.get(i));
|
||||
quester.setCurrentQuests(currentQuests);
|
||||
}
|
||||
}
|
||||
final ConfigurationSection dataSec = data.getConfigurationSection("questData");
|
||||
if (dataSec == null || dataSec.getKeys(false).isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
for (final String key : dataSec.getKeys(false)) {
|
||||
final ConfigurationSection questSec = dataSec.getConfigurationSection(key);
|
||||
final Quest quest = plugin.getQuest(key);
|
||||
Stage stage;
|
||||
if (quest == null || quester.getCurrentQuests().containsKey(quest) == false) {
|
||||
continue;
|
||||
}
|
||||
stage = quester.getCurrentStage(quest);
|
||||
if (stage == null) {
|
||||
quest.completeQuest(quester);
|
||||
plugin.getLogger().severe("[Quests] Invalid stage number for player: \"" + uniqueId + "\" on Quest \""
|
||||
+ quest.getName() + "\". Quest ended.");
|
||||
continue;
|
||||
}
|
||||
quester.addEmptiesFor(quest, quester.getCurrentQuests().get(quest));
|
||||
if (questSec == null)
|
||||
continue;
|
||||
if (questSec.contains("blocks-broken-names")) {
|
||||
final List<String> names = questSec.getStringList("blocks-broken-names");
|
||||
final List<Integer> amounts = questSec.getIntegerList("blocks-broken-amounts");
|
||||
final List<Short> durability = questSec.getShortList("blocks-broken-durability");
|
||||
int index = 0;
|
||||
for (final String s : names) {
|
||||
ItemStack is;
|
||||
try {
|
||||
is = new ItemStack(Material.matchMaterial(s), amounts.get(index), durability.get(index));
|
||||
} catch (final IndexOutOfBoundsException e) {
|
||||
// Legacy
|
||||
is = new ItemStack(Material.matchMaterial(s), amounts.get(index), (short) 0);
|
||||
}
|
||||
if (quester.getQuestData(quest).blocksBroken.size() > 0) {
|
||||
quester.getQuestData(quest).blocksBroken.set(index, is);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
if (questSec.contains("blocks-damaged-names")) {
|
||||
final List<String> names = questSec.getStringList("blocks-damaged-names");
|
||||
final List<Integer> amounts = questSec.getIntegerList("blocks-damaged-amounts");
|
||||
final List<Short> durability = questSec.getShortList("blocks-damaged-durability");
|
||||
int index = 0;
|
||||
for (final String s : names) {
|
||||
ItemStack is;
|
||||
try {
|
||||
is = new ItemStack(Material.matchMaterial(s), amounts.get(index), durability.get(index));
|
||||
} catch (final IndexOutOfBoundsException e) {
|
||||
// Legacy
|
||||
is = new ItemStack(Material.matchMaterial(s), amounts.get(index), (short) 0);
|
||||
}
|
||||
if (quester.getQuestData(quest).blocksDamaged.size() > 0) {
|
||||
quester.getQuestData(quest).blocksDamaged.set(index, is);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
if (questSec.contains("blocks-placed-names")) {
|
||||
final List<String> names = questSec.getStringList("blocks-placed-names");
|
||||
final List<Integer> amounts = questSec.getIntegerList("blocks-placed-amounts");
|
||||
final List<Short> durability = questSec.getShortList("blocks-placed-durability");
|
||||
int index = 0;
|
||||
for (final String s : names) {
|
||||
ItemStack is;
|
||||
try {
|
||||
is = new ItemStack(Material.matchMaterial(s), amounts.get(index), durability.get(index));
|
||||
} catch (final IndexOutOfBoundsException e) {
|
||||
// Legacy
|
||||
is = new ItemStack(Material.matchMaterial(s), amounts.get(index), (short) 0);
|
||||
}
|
||||
if (quester.getQuestData(quest).blocksPlaced.size() > 0) {
|
||||
quester.getQuestData(quest).blocksPlaced.set(index, is);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
if (questSec.contains("blocks-used-names")) {
|
||||
final List<String> names = questSec.getStringList("blocks-used-names");
|
||||
final List<Integer> amounts = questSec.getIntegerList("blocks-used-amounts");
|
||||
final List<Short> durability = questSec.getShortList("blocks-used-durability");
|
||||
int index = 0;
|
||||
for (final String s : names) {
|
||||
ItemStack is;
|
||||
try {
|
||||
is = new ItemStack(Material.matchMaterial(s), amounts.get(index), durability.get(index));
|
||||
} catch (final IndexOutOfBoundsException e) {
|
||||
// Legacy
|
||||
is = new ItemStack(Material.matchMaterial(s), amounts.get(index), (short) 0);
|
||||
}
|
||||
if (quester.getQuestData(quest).blocksUsed.size() > 0) {
|
||||
quester.getQuestData(quest).blocksUsed.set(index, is);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
if (questSec.contains("blocks-cut-names")) {
|
||||
final List<String> names = questSec.getStringList("blocks-cut-names");
|
||||
final List<Integer> amounts = questSec.getIntegerList("blocks-cut-amounts");
|
||||
final List<Short> durability = questSec.getShortList("blocks-cut-durability");
|
||||
int index = 0;
|
||||
for (final String s : names) {
|
||||
ItemStack is;
|
||||
try {
|
||||
is = new ItemStack(Material.matchMaterial(s), amounts.get(index), durability.get(index));
|
||||
} catch (final IndexOutOfBoundsException e) {
|
||||
// Legacy
|
||||
is = new ItemStack(Material.matchMaterial(s), amounts.get(index), (short) 0);
|
||||
}
|
||||
if (quester.getQuestData(quest).blocksCut.size() > 0) {
|
||||
quester.getQuestData(quest).blocksCut.set(index, is);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
if (questSec.contains("item-craft-amounts")) {
|
||||
final List<Integer> craftAmounts = questSec.getIntegerList("item-craft-amounts");
|
||||
for (int i = 0; i < craftAmounts.size(); i++) {
|
||||
if (i < quester.getCurrentStage(quest).getItemsToCraft().size()) {
|
||||
quester.getQuestData(quest).itemsCrafted.put(quester.getCurrentStage(quest)
|
||||
.getItemsToCraft().get(i), craftAmounts.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (questSec.contains("item-smelt-amounts")) {
|
||||
final List<Integer> smeltAmounts = questSec.getIntegerList("item-smelt-amounts");
|
||||
for (int i = 0; i < smeltAmounts.size(); i++) {
|
||||
if (i < quester.getCurrentStage(quest).getItemsToSmelt().size()) {
|
||||
quester.getQuestData(quest).itemsSmelted.put(quester.getCurrentStage(quest)
|
||||
.getItemsToSmelt().get(i), smeltAmounts.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (questSec.contains("item-enchant-amounts")) {
|
||||
final List<Integer> enchantAmounts = questSec.getIntegerList("item-enchant-amounts");
|
||||
for (int i = 0; i < enchantAmounts.size(); i++) {
|
||||
if (i < quester.getCurrentStage(quest).getItemsToEnchant().size()) {
|
||||
quester.getQuestData(quest).itemsEnchanted.put(quester.getCurrentStage(quest)
|
||||
.getItemsToEnchant().get(i), enchantAmounts.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (questSec.contains("item-brew-amounts")) {
|
||||
final List<Integer> brewAmounts = questSec.getIntegerList("item-brew-amounts");
|
||||
for (int i = 0; i < brewAmounts.size(); i++) {
|
||||
if (i < quester.getCurrentStage(quest).getItemsToBrew().size()) {
|
||||
quester.getQuestData(quest).itemsBrewed.put(quester.getCurrentStage(quest)
|
||||
.getItemsToBrew().get(i), brewAmounts.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (questSec.contains("item-consume-amounts")) {
|
||||
final List<Integer> consumeAmounts = questSec.getIntegerList("item-consume-amounts");
|
||||
for (int i = 0; i < consumeAmounts.size(); i++) {
|
||||
if (i < quester.getCurrentStage(quest).getItemsToConsume().size()) {
|
||||
quester.getQuestData(quest).itemsConsumed.put(quester.getCurrentStage(quest)
|
||||
.getItemsToConsume().get(i), consumeAmounts.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (questSec.contains("cows-milked")) {
|
||||
quester.getQuestData(quest).setCowsMilked(questSec.getInt("cows-milked"));
|
||||
}
|
||||
if (questSec.contains("fish-caught")) {
|
||||
quester.getQuestData(quest).setFishCaught(questSec.getInt("fish-caught"));
|
||||
}
|
||||
if (questSec.contains("players-killed")) {
|
||||
quester.getQuestData(quest).setPlayersKilled(questSec.getInt("players-killed"));
|
||||
}
|
||||
if (questSec.contains("mobs-killed")) {
|
||||
final LinkedList<EntityType> mobs = new LinkedList<EntityType>();
|
||||
final List<Integer> amounts = questSec.getIntegerList("mobs-killed-amounts");
|
||||
for (final String s : questSec.getStringList("mobs-killed")) {
|
||||
final EntityType mob = MiscUtil.getProperMobType(s);
|
||||
if (mob != null) {
|
||||
mobs.add(mob);
|
||||
}
|
||||
quester.getQuestData(quest).mobsKilled.clear();
|
||||
quester.getQuestData(quest).mobNumKilled.clear();
|
||||
for (final EntityType e : mobs) {
|
||||
quester.getQuestData(quest).mobsKilled.add(e);
|
||||
quester.getQuestData(quest).mobNumKilled.add(amounts.get(mobs.indexOf(e)));
|
||||
}
|
||||
if (questSec.contains("mob-kill-locations")) {
|
||||
final LinkedList<Location> locations = new LinkedList<Location>();
|
||||
final List<Integer> radii = questSec.getIntegerList("mob-kill-location-radii");
|
||||
for (final String loc : questSec.getStringList("mob-kill-locations")) {
|
||||
if (ConfigUtil.getLocation(loc) != null) {
|
||||
locations.add(ConfigUtil.getLocation(loc));
|
||||
}
|
||||
}
|
||||
quester.getQuestData(quest).locationsToKillWithin = locations;
|
||||
quester.getQuestData(quest).radiiToKillWithin.clear();
|
||||
for (final int i : radii) {
|
||||
quester.getQuestData(quest).radiiToKillWithin.add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (questSec.contains("item-delivery-amounts")) {
|
||||
final List<Integer> deliveryAmounts = questSec.getIntegerList("item-delivery-amounts");
|
||||
int index = 0;
|
||||
for (final int amt : deliveryAmounts) {
|
||||
final ItemStack is = quester.getCurrentStage(quest).getItemsToDeliver().get(index);
|
||||
final ItemStack temp = new ItemStack(is.getType(), amt, is.getDurability());
|
||||
try {
|
||||
temp.addEnchantments(is.getEnchantments());
|
||||
} catch (final Exception e) {
|
||||
plugin.getLogger().warning("Unable to add enchantment(s) " + is.getEnchantments().toString()
|
||||
+ " to delivery item " + is.getType().name() + " x " + amt + " for quest "
|
||||
+ quest.getName());
|
||||
}
|
||||
temp.setItemMeta(is.getItemMeta());
|
||||
if (quester.getQuestData(quest).itemsDelivered.size() > 0) {
|
||||
quester.getQuestData(quest).itemsDelivered.set(index, temp);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
if (questSec.contains("citizen-ids-to-talk-to")) {
|
||||
final List<Integer> ids = questSec.getIntegerList("citizen-ids-to-talk-to");
|
||||
final List<Boolean> has = questSec.getBooleanList("has-talked-to");
|
||||
for (final int i : ids) {
|
||||
quester.getQuestData(quest).citizensInteracted.put(i, has.get(ids.indexOf(i)));
|
||||
}
|
||||
}
|
||||
if (questSec.contains("citizen-ids-killed")) {
|
||||
final List<Integer> ids = questSec.getIntegerList("citizen-ids-killed");
|
||||
final List<Integer> num = questSec.getIntegerList("citizen-amounts-killed");
|
||||
quester.getQuestData(quest).citizensKilled.clear();
|
||||
quester.getQuestData(quest).citizenNumKilled.clear();
|
||||
for (final int i : ids) {
|
||||
quester.getQuestData(quest).citizensKilled.add(i);
|
||||
quester.getQuestData(quest).citizenNumKilled.add(num.get(ids.indexOf(i)));
|
||||
}
|
||||
}
|
||||
if (questSec.contains("locations-to-reach")) {
|
||||
final LinkedList<Location> locations = new LinkedList<Location>();
|
||||
final List<Boolean> has = questSec.getBooleanList("has-reached-location");
|
||||
while (has.size() < locations.size()) {
|
||||
// TODO - Find proper cause of Github issues #646 and #825
|
||||
plugin.getLogger().info("Added missing has-reached-location data for Quester " + uniqueId);
|
||||
has.add(false);
|
||||
}
|
||||
final List<Integer> radii = questSec.getIntegerList("radii-to-reach-within");
|
||||
for (final String loc : questSec.getStringList("locations-to-reach")) {
|
||||
if (ConfigUtil.getLocation(loc) != null) {
|
||||
locations.add(ConfigUtil.getLocation(loc));
|
||||
}
|
||||
}
|
||||
quester.getQuestData(quest).locationsReached = locations;
|
||||
quester.getQuestData(quest).hasReached.clear();
|
||||
quester.getQuestData(quest).radiiToReachWithin.clear();
|
||||
for (final boolean b : has) {
|
||||
quester.getQuestData(quest).hasReached.add(b);
|
||||
}
|
||||
for (final int i : radii) {
|
||||
quester.getQuestData(quest).radiiToReachWithin.add(i);
|
||||
}
|
||||
}
|
||||
if (questSec.contains("mobs-to-tame")) {
|
||||
final List<String> mobs = questSec.getStringList("mobs-to-tame");
|
||||
final List<Integer> amounts = questSec.getIntegerList("mob-tame-amounts");
|
||||
for (final String mob : mobs) {
|
||||
quester.getQuestData(quest).mobsTamed.put(EntityType.valueOf(mob.toUpperCase()), amounts
|
||||
.get(mobs.indexOf(mob)));
|
||||
}
|
||||
}
|
||||
if (questSec.contains("sheep-to-shear")) {
|
||||
final List<String> colors = questSec.getStringList("sheep-to-shear");
|
||||
final List<Integer> amounts = questSec.getIntegerList("sheep-sheared");
|
||||
for (final String color : colors) {
|
||||
quester.getQuestData(quest).sheepSheared.put(MiscUtil.getProperDyeColor(color), amounts.get(colors
|
||||
.indexOf(color)));
|
||||
}
|
||||
}
|
||||
if (questSec.contains("passwords")) {
|
||||
final List<String> passwords = questSec.getStringList("passwords");
|
||||
final List<Boolean> said = questSec.getBooleanList("passwords-said");
|
||||
for (int i = 0; i < passwords.size(); i++) {
|
||||
quester.getQuestData(quest).passwordsSaid.put(passwords.get(i), said.get(i));
|
||||
}
|
||||
}
|
||||
if (questSec.contains("custom-objectives")) {
|
||||
final List<String> customObj = questSec.getStringList("custom-objectives");
|
||||
final List<Integer> customObjCount = questSec.getIntegerList("custom-objective-counts");
|
||||
for (int i = 0; i < customObj.size(); i++) {
|
||||
quester.getQuestData(quest).customObjectiveCounts.put(customObj.get(i), customObjCount.get(i));
|
||||
}
|
||||
}
|
||||
if (questSec.contains("stage-delay")) {
|
||||
quester.getQuestData(quest).setDelayTimeLeft(questSec.getLong("stage-delay"));
|
||||
}
|
||||
if (quester.getCurrentStage(quest).getChatActions().isEmpty() == false) {
|
||||
for (final String chatTrig : quester.getCurrentStage(quest).getChatActions().keySet()) {
|
||||
quester.getQuestData(quest).actionFired.put(chatTrig, false);
|
||||
}
|
||||
}
|
||||
if (questSec.contains("chat-triggers")) {
|
||||
final List<String> chatTriggers = questSec.getStringList("chat-triggers");
|
||||
for (final String s : chatTriggers) {
|
||||
quester.getQuestData(quest).actionFired.put(s, true);
|
||||
}
|
||||
}
|
||||
if (quester.getCurrentStage(quest).getCommandActions().isEmpty() == false) {
|
||||
for (final String commandTrig : quester.getCurrentStage(quest).getCommandActions().keySet()) {
|
||||
quester.getQuestData(quest).actionFired.put(commandTrig, false);
|
||||
}
|
||||
}
|
||||
if (questSec.contains("command-triggers")) {
|
||||
final List<String> commandTriggers = questSec.getStringList("command-triggers");
|
||||
for (final String s : commandTriggers) {
|
||||
quester.getQuestData(quest).actionFired.put(s, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return quester;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveQuesterData(final Quester quester) throws Exception {
|
||||
final FileConfiguration data = quester.getBaseData();
|
||||
try {
|
||||
data.save(new File(directoryPath + File.separator + quester.getUUID() + ".yml"));
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteQuesterData(final UUID uniqueId) throws Exception {
|
||||
final File f = new File(directoryPath + File.separator + uniqueId + ".yml");
|
||||
f.delete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQuesterLastKnownName(final UUID uniqueId) throws Exception {
|
||||
final FileConfiguration data = new YamlConfiguration();
|
||||
Quester quester = plugin.getQuester(uniqueId);
|
||||
if (quester != null) {
|
||||
quester.hardClear();
|
||||
} else {
|
||||
quester = new Quester(plugin, uniqueId);
|
||||
}
|
||||
return data.getString("lastKnownName");
|
||||
}
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
/*******************************************************************************************************
|
||||
* Continued by PikaMug (formerly HappyPikachu) with permission from _Blackvein_. All rights reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************************************/
|
||||
|
||||
package me.blackvein.quests.storage.implementation.sql;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
|
||||
import me.blackvein.quests.Quester;
|
||||
import me.blackvein.quests.Quests;
|
||||
import me.blackvein.quests.storage.implementation.StorageImplementation;
|
||||
import me.blackvein.quests.storage.implementation.sql.connection.ConnectionFactory;
|
||||
|
||||
public class SqlStorage implements StorageImplementation {
|
||||
private static final String PLAYER_SELECT = "SELECT id, hasjournal, FROM '{prefix}players' WHERE uuid=?";
|
||||
private static final String PLAYER_SELECT_USERNAME_BY_UUID = "SELECT username FROM '{prefix}players' WHERE uuid=? LIMIT 1";
|
||||
private static final String PLAYER_UPDATE_USERNAME_FOR_UUID = "UPDATE '{prefix}players' SET username=? WHERE uuid=?";
|
||||
private static final String PLAYER_INSERT = "INSERT INTO '{prefix}players' (uuid, username, hasjournal) VALUES(?, ?, ?) ON DUPLICATE KEY UPDATE";
|
||||
private static final String PLAYER_DELETE = "DELETE FROM '{prefix}players' WHERE uuid=?";
|
||||
|
||||
private final Quests plugin;
|
||||
|
||||
private final ConnectionFactory connectionFactory;
|
||||
private final Function<String, String> statementProcessor;
|
||||
|
||||
public SqlStorage(final Quests plugin, final ConnectionFactory connectionFactory, final String tablePrefix) {
|
||||
this.plugin = plugin;
|
||||
this.connectionFactory = connectionFactory;
|
||||
this.statementProcessor = connectionFactory.getStatementProcessor().compose(s -> s.replace("{prefix}", tablePrefix));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Quests getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getImplementationName() {
|
||||
return connectionFactory.getImplementationName();
|
||||
}
|
||||
|
||||
public ConnectionFactory getConnectionFactory() {
|
||||
return connectionFactory;
|
||||
}
|
||||
|
||||
public Function<String, String> getStatementProcessor() {
|
||||
return statementProcessor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() throws Exception {
|
||||
connectionFactory.init(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
connectionFactory.close();
|
||||
} catch (final Exception e) {
|
||||
this.plugin.getLogger().severe("Problem occurred while closing SQL storage");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Quester loadQuesterData(final UUID uniqueId) throws Exception {
|
||||
final Quester quester = new Quester(plugin, uniqueId);
|
||||
try (Connection c = connectionFactory.getConnection()) {
|
||||
if (uniqueId != null) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(PLAYER_SELECT))) {
|
||||
ps.setString(1, uniqueId.toString());
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
final boolean hasJournal = rs.getBoolean("hasjournal");
|
||||
quester.hasJournal = hasJournal;
|
||||
// TODO the rest
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return quester;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveQuesterData(final Quester quester) throws Exception {
|
||||
final UUID uniqueId = quester.getUUID();
|
||||
final String username = quester.getPlayer().getName();
|
||||
final String oldUsername = getQuesterLastKnownName(uniqueId);
|
||||
|
||||
try (Connection c = connectionFactory.getConnection()) {
|
||||
if (oldUsername != null && !username.equals(oldUsername)) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(PLAYER_UPDATE_USERNAME_FOR_UUID))) {
|
||||
ps.setString(1, username);
|
||||
ps.setString(2, uniqueId.toString());
|
||||
ps.execute();
|
||||
}
|
||||
} else {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(PLAYER_INSERT))) {
|
||||
ps.setString(1, uniqueId.toString());
|
||||
ps.setString(2, username);
|
||||
ps.setBoolean(3, quester.hasJournal);
|
||||
ps.execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!username.equals(oldUsername)) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteQuesterData(final UUID uniqueId) throws Exception {
|
||||
try (Connection c = connectionFactory.getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(PLAYER_DELETE))) {
|
||||
ps.setString(1, uniqueId.toString());
|
||||
ps.execute();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQuesterLastKnownName(final UUID uniqueId) throws Exception {
|
||||
try (Connection c = connectionFactory.getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(PLAYER_SELECT_USERNAME_BY_UUID))) {
|
||||
ps.setString(1, uniqueId.toString());
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
return rs.getString("username");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*******************************************************************************************************
|
||||
* Continued by PikaMug (formerly HappyPikachu) with permission from _Blackvein_. All rights reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************************************/
|
||||
|
||||
package me.blackvein.quests.storage.implementation.sql.connection;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import me.blackvein.quests.Quests;
|
||||
|
||||
public interface ConnectionFactory {
|
||||
String getImplementationName();
|
||||
|
||||
void init(Quests plugin);
|
||||
|
||||
void close() throws Exception;
|
||||
|
||||
default Map<String, String> getMeta() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Function<String, String> getStatementProcessor();
|
||||
|
||||
Connection getConnection() throws SQLException;
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
/*******************************************************************************************************
|
||||
* Continued by PikaMug (formerly HappyPikachu) with permission from _Blackvein_. All rights reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************************************/
|
||||
|
||||
package me.blackvein.quests.storage.implementation.sql.connection.hikari;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
|
||||
import me.blackvein.quests.Quests;
|
||||
import me.blackvein.quests.storage.implementation.sql.connection.ConnectionFactory;
|
||||
import me.blackvein.quests.storage.misc.StorageCredentials;
|
||||
|
||||
public abstract class HikariConnectionFactory implements ConnectionFactory {
|
||||
private final StorageCredentials configuration;
|
||||
private HikariDataSource hikari;
|
||||
|
||||
public HikariConnectionFactory(final StorageCredentials configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default port used by the database
|
||||
*
|
||||
* @return the default port
|
||||
*/
|
||||
protected abstract String defaultPort();
|
||||
|
||||
/**
|
||||
* Configures the {@link HikariConfig} with the relevant database properties.
|
||||
*
|
||||
* <p>Each driver does this slightly differently.</p>
|
||||
*
|
||||
* @param config the hikari config
|
||||
* @param address the database address
|
||||
* @param port the database port
|
||||
* @param databaseName the database name
|
||||
* @param username the database username
|
||||
* @param password the database password
|
||||
*/
|
||||
protected abstract void configureDatabase(HikariConfig config, String address, String port, String databaseName,
|
||||
String username, String password);
|
||||
|
||||
/**
|
||||
* Allows the connection factory instance to override certain properties before they are set.
|
||||
*
|
||||
* @param properties the current properties
|
||||
*/
|
||||
protected void overrideProperties(final Map<String, String> properties) {
|
||||
// https://github.com/brettwooldridge/HikariCP/wiki/Rapid-Recovery
|
||||
properties.putIfAbsent("socketTimeout", String.valueOf(TimeUnit.SECONDS.toMillis(30)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the given connection properties onto the config.
|
||||
*
|
||||
* @param config the hikari config
|
||||
* @param properties the properties
|
||||
*/
|
||||
protected void setProperties(final HikariConfig config, final Map<String, String> properties) {
|
||||
for (final Map.Entry<String, String> property : properties.entrySet()) {
|
||||
config.addDataSourceProperty(property.getKey(), property.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(final Quests plugin) {
|
||||
final HikariConfig config = new HikariConfig();
|
||||
config.setPoolName("quests-hikari");
|
||||
|
||||
final String[] addressSplit = configuration.getAddress().split(":");
|
||||
final String address = addressSplit[0];
|
||||
final String port = addressSplit.length > 1 ? addressSplit[1] : defaultPort();
|
||||
|
||||
configureDatabase(config, address, port, configuration.getDatabase(), configuration.getUsername(),
|
||||
configuration.getPassword());
|
||||
|
||||
final Map<String, String> properties = new HashMap<>(this.configuration.getProperties());
|
||||
|
||||
overrideProperties(properties);
|
||||
|
||||
setProperties(config, properties);
|
||||
|
||||
config.setMaximumPoolSize(this.configuration.getMaxPoolSize());
|
||||
config.setMinimumIdle(this.configuration.getMinIdleConnections());
|
||||
config.setMaxLifetime(this.configuration.getMaxLifetime());
|
||||
config.setConnectionTimeout(this.configuration.getConnectionTimeout());
|
||||
|
||||
hikari = new HikariDataSource(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (hikari != null) {
|
||||
hikari.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
if (hikari == null) {
|
||||
throw new SQLException("Unable to get a connection from the pool because hikari is null");
|
||||
}
|
||||
|
||||
final Connection connection = hikari.getConnection();
|
||||
if (connection == null) {
|
||||
throw new SQLException("Unable to get a connection from the pool because getConnection returned null");
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
public static String identifyClassLoader(final ClassLoader classLoader) throws ReflectiveOperationException {
|
||||
final Class<?> pluginClassLoaderClass = Class.forName("org.bukkit.plugin.java.PluginClassLoader");
|
||||
if (pluginClassLoaderClass.isInstance(classLoader)) {
|
||||
final Method getPluginMethod = pluginClassLoaderClass.getDeclaredMethod("getPlugin");
|
||||
getPluginMethod.setAccessible(true);
|
||||
|
||||
final JavaPlugin plugin = (JavaPlugin) getPluginMethod.invoke(classLoader);
|
||||
return plugin.getName();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/*******************************************************************************************************
|
||||
* Continued by PikaMug (formerly HappyPikachu) with permission from _Blackvein_. All rights reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************************************/
|
||||
|
||||
package me.blackvein.quests.storage.implementation.sql.connection.hikari;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
|
||||
import me.blackvein.quests.storage.misc.StorageCredentials;
|
||||
|
||||
public class MySqlConnectionFactory extends HikariConnectionFactory {
|
||||
public MySqlConnectionFactory(final StorageCredentials configuration) {
|
||||
super(configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getImplementationName() {
|
||||
return "MySQL";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String defaultPort() {
|
||||
return "3306";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureDatabase(final HikariConfig config, final String address, final String port,
|
||||
final String databaseName, final String username, final String password) {
|
||||
config.setDriverClassName("com.mysql.cj.jdbc.NonRegisteringDriver");
|
||||
config.setJdbcUrl("jdbc:mysql://" + address + ":" + port + "/" + databaseName);
|
||||
config.setUsername(username);
|
||||
config.setPassword(password);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void overrideProperties(final Map<String, String> properties) {
|
||||
// https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration
|
||||
properties.putIfAbsent("cachePrepStmts", "true");
|
||||
properties.putIfAbsent("prepStmtCacheSize", "250");
|
||||
properties.putIfAbsent("prepStmtCacheSqlLimit", "2048");
|
||||
properties.putIfAbsent("useServerPrepStmts", "true");
|
||||
properties.putIfAbsent("useLocalSessionState", "true");
|
||||
properties.putIfAbsent("rewriteBatchedStatements", "true");
|
||||
properties.putIfAbsent("cacheResultSetMetadata", "true");
|
||||
properties.putIfAbsent("cacheServerConfiguration", "true");
|
||||
properties.putIfAbsent("elideSetAutoCommits", "true");
|
||||
properties.putIfAbsent("maintainTimeStats", "false");
|
||||
properties.putIfAbsent("alwaysSendSetIsolation", "false");
|
||||
properties.putIfAbsent("cacheCallableStmts", "true");
|
||||
|
||||
// https://stackoverflow.com/a/54256150
|
||||
properties.putIfAbsent("serverTimezone", "UTC");
|
||||
|
||||
super.overrideProperties(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Function<String, String> getStatementProcessor() {
|
||||
return s -> s.replace("'", "`");
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*******************************************************************************************************
|
||||
* Continued by PikaMug (formerly HappyPikachu) with permission from _Blackvein_. All rights reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************************************/
|
||||
|
||||
package me.blackvein.quests.storage.misc;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class StorageCredentials {
|
||||
|
||||
private final String address;
|
||||
private final String database;
|
||||
private final String username;
|
||||
private final String password;
|
||||
private final int maxPoolSize;
|
||||
private final int minIdleConnections;
|
||||
private final int maxLifetime;
|
||||
private final int connectionTimeout;
|
||||
private final Map<String, String> properties;
|
||||
|
||||
public StorageCredentials(final String address, final String database, final String username, final String password,
|
||||
final int maxPoolSize, final int minIdleConnections, final int maxLifetime, final int connectionTimeout,
|
||||
final Map<String, String> properties) {
|
||||
this.address = address;
|
||||
this.database = database;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.maxPoolSize = maxPoolSize;
|
||||
this.minIdleConnections = minIdleConnections;
|
||||
this.maxLifetime = maxLifetime;
|
||||
this.connectionTimeout = connectionTimeout;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return Objects.requireNonNull(address, "address");
|
||||
}
|
||||
|
||||
public String getDatabase() {
|
||||
return Objects.requireNonNull(database, "database");
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return Objects.requireNonNull(username, "username");
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return Objects.requireNonNull(password, "password");
|
||||
}
|
||||
|
||||
public int getMaxPoolSize() {
|
||||
return maxPoolSize;
|
||||
}
|
||||
|
||||
public int getMinIdleConnections() {
|
||||
return minIdleConnections;
|
||||
}
|
||||
|
||||
public int getMaxLifetime() {
|
||||
return maxLifetime;
|
||||
}
|
||||
|
||||
public int getConnectionTimeout() {
|
||||
return connectionTimeout;
|
||||
}
|
||||
|
||||
public Map<String, String> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
}
|
@ -19,6 +19,18 @@ npc-effects:
|
||||
show-requirements: true
|
||||
show-titles: true
|
||||
strict-player-movement: 0
|
||||
storage-data:
|
||||
address: localhost
|
||||
database: minecraft
|
||||
username: root
|
||||
password: ''
|
||||
table_prefix: 'quests_'
|
||||
pool-settings:
|
||||
max-pool-size: 10
|
||||
min-idle: 10
|
||||
max-lifetime: 1800000
|
||||
connection-timeout: 5000
|
||||
storage-method: yaml
|
||||
top-limit: 150
|
||||
translate-names: true
|
||||
translate-subcommands: false
|
Loading…
Reference in New Issue
Block a user