diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 00000000..a3961dfa
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,13 @@
+# These are supported funding model platforms
+
+github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
+patreon: # Replace with a single Patreon username
+open_collective: # Replace with a single Open Collective username
+ko_fi: skytasul
+tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
+community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
+liberapay: # Replace with a single Liberapay username
+issuehunt: # Replace with a single IssueHunt username
+otechie: # Replace with a single Otechie username
+lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
+custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
\ No newline at end of file
diff --git a/README.md b/README.md
index 3476daf3..e5e5404e 100644
--- a/README.md
+++ b/README.md
@@ -51,12 +51,12 @@ In *pom.xml*, add this to the `repositories` section:
https://repo.codemc.org/repository/maven-public
```
-And add this to the `dependencies` section: (replace VERSION by whatever version you want, i.e. `0.19.2`, `0.19.3-SNAPSHOT`...)
+And add this to the `dependencies` section: (replace VERSION by whatever version you want, i.e. `0.19.7`, `0.20-SNAPSHOT`...)
```xml
fr.skytasul
beautyquests-core
VERSION
- compile
+ provided
```
diff --git a/core/libs.sh b/core/libs.sh
index 896cf1ef..91882d9a 100644
--- a/core/libs.sh
+++ b/core/libs.sh
@@ -16,14 +16,15 @@ echo -e "Maven path: $mavenPath\e[39m"
"$mavenPath" install:install-file -Dfile=$jarsPath/Factions.jar -DgroupId=com.massivecraft -DartifactId=factions -Dversion=1.0 -Dpackaging=jar
"$mavenPath" install:install-file -Dfile=$jarsPath/MassiveCore.jar -DgroupId=com.massivecraft -DartifactId=massivecore -Dversion=1.0 -Dpackaging=jar
"$mavenPath" install:install-file -Dfile=$jarsPath/GPS.jar -DgroupId=com.live.bemmamin -DartifactId=gps -Dversion=1.0 -Dpackaging=jar
-"$mavenPath" install:install-file -Dfile=$jarsPath/Jobs.jar -DgroupId=com.gamingmesh -DartifactId=jobs -Dversion=5.0.0.9 -Dpackaging=jar
+"$mavenPath" install:install-file -Dfile=$jarsPath/Jobs.jar -DgroupId=com.gamingmesh -DartifactId=jobs -Dversion=5.1.0.1 -Dpackaging=jar
"$mavenPath" install:install-file -Dfile=$jarsPath/McCombatLevel.jar -DgroupId=com.gmail.mrphpfan -DartifactId=mccombatlevel -Dversion=1.0 -Dpackaging=jar
"$mavenPath" install:install-file -Dfile=$jarsPath/mcMMO.jar -DgroupId=com.gmail.nossr50 -DartifactId=mcmmo -Dversion=1.0 -Dpackaging=jar
"$mavenPath" install:install-file -Dfile=$jarsPath/SkillAPI.jar -DgroupId=com.suxy -DartifactId=skillapi -Dversion=1.0 -Dpackaging=jar
"$mavenPath" install:install-file -Dfile=$jarsPath/Boss.jar -DgroupId=org.mineacademy -DartifactId=boss -Dversion=4.2.1 -Dpackaging=jar
"$mavenPath" install:install-file -Dfile=$jarsPath/CMI.jar -DgroupId=com.zrips -DartifactId=cmi -Dversion=9.0.2.1 -Dpackaging=jar
-"$mavenPath" install:install-file -Dfile=$jarsPath/CMILib.jar -DgroupId=com.zrips -DartifactId=cmilib -Dversion=1.0.4.1 -Dpackaging=jar
+"$mavenPath" install:install-file -Dfile=$jarsPath/CMILib.jar -DgroupId=com.zrips -DartifactId=cmilib -Dversion=1.2.3.3 -Dpackaging=jar
"$mavenPath" install:install-file -Dfile=$jarsPath/UltimateTimber.jar -DgroupId=com.songoda -DartifactId=ultimatetimber -Dversion=2.2.5 -Dpackaging=jar
+"$mavenPath" install:install-file -Dfile=$jarsPath/AdvancedSpawners-API.jar -DgroupId=gcspawners -DartifactId=gcspawners -Dversion=3.3.0 -Dpackaging=jar
#"$mavenPath" install:install-file -Dfile=$jarsPath/MythicMobs.jar -DgroupId=io.lumine.xikage -DartifactId=MythicMobs -Dversion=4.12.0 -Dpackaging=jar
#"$mavenPath" install:install-file -Dfile=$jarsPath/TokenEnchantAPI.jar -DgroupId=com.vk2gpz.tokenenchant -DartifactId=TokenEnchantAPI -Dversion=18.15.2 -Dpackaging=jar
diff --git a/core/pom.xml b/core/pom.xml
index f16dc7e8..282d4d95 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -8,7 +8,7 @@
fr.skytasul
beautyquests-parent
- 0.19.7
+ 0.20.0
@@ -20,6 +20,7 @@
*.yml
locales/*.yml
+ *.properties
@@ -43,9 +44,17 @@
fr.skytasul.quests.utils.configupdater
- de.jeff_media.updatechecker
+ com.jeff_media.updatechecker
fr.skytasul.quests.utils.updatechecker
+
+ revxrsal.commands
+ fr.skytasul.quests.commands.revxrsal
+
+
+ com.zaxxer.hikari
+ fr.skytasul.quests.utils.hikari
+
@@ -57,10 +66,28 @@
+
+ maven-compiler-plugin
+ 3.8.0
+
+ true
+
+
+
+ maven-javadoc-plugin
+ 3.4.1
+
+ false
+
+
+
+ papermc
+ https://repo.papermc.io/repository/maven-public/
+
placeholderapi
https://repo.extendedclip.com/content/repositories/placeholderapi/
@@ -75,7 +102,7 @@
codemc-repo
- https://repo.codemc.org/repository/maven-public/
+ https://repo.codemc.io/repository/maven-public/
mineacademy-repo
@@ -117,13 +144,17 @@
jeff-media-public
https://hub.jeff-media.com/nexus/repository/jeff-media-public/
+
+ bg-repo
+ https://repo.bg-software.com/repository/api/
+
- org.spigotmc
- spigot
- 1.18.2-R0.1-SNAPSHOT
+ io.papermc.paper
+ paper-api
+ 1.19.2-R0.1-SNAPSHOT
provided
@@ -213,7 +244,7 @@
io.lumine
Mythic-Dist
- 5.0.1
+ 5.2.0
provided
@@ -225,13 +256,13 @@
com.github.BlueMap-Minecraft
BlueMapAPI
- v1.7.0
+ v2.1.0
provided
- de.jeff_media
+ com.jeff_media
SpigotUpdateChecker
- 1.3.2
+ 3.0.0
compile
@@ -241,10 +272,43 @@
provided
- org.mariadb.jdbc
- mariadb-java-client
+ com.github.decentsoftware-eu
+ decentholograms
2.7.5
- provided
+ provided
+
+
+ com.github.Flo0
+ PlayerBlockTracker
+ 1.0.2
+ provided
+
+
+ com.github.lokka30
+ LevelledMobs
+ 3.2.6
+ provided
+
+
+ com.bgsoftware
+ WildStackerAPI
+ 2022.6
+ provided
+
+
+ com.github.Revxrsal.Lamp
+ bukkit
+ d72483065c
+
+
+ com.github.Revxrsal.Lamp
+ common
+ d72483065c
+
+
+ com.zaxxer
+ HikariCP
+ 4.0.3
@@ -287,7 +351,7 @@
com.gamingmesh
jobs
- 5.0.0.9
+ 5.1.0.1
provided
@@ -317,7 +381,13 @@
com.zrips
cmilib
- 1.0.4.1
+ 1.2.3.3
+ provided
+
+
+ gcspawners
+ gcspawners
+ 3.3.0
provided
diff --git a/core/src/main/java/fr/skytasul/quests/BeautyQuests.java b/core/src/main/java/fr/skytasul/quests/BeautyQuests.java
index bbd5d13f..2b5aeac6 100644
--- a/core/src/main/java/fr/skytasul/quests/BeautyQuests.java
+++ b/core/src/main/java/fr/skytasul/quests/BeautyQuests.java
@@ -2,9 +2,6 @@
import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -12,31 +9,31 @@
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
+import java.util.function.Function;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
-
import org.bstats.bukkit.Metrics;
+import org.bstats.charts.AdvancedPie;
import org.bstats.charts.DrilldownPie;
import org.bstats.charts.SimplePie;
import org.bstats.charts.SingleLineChart;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
-import org.bukkit.command.PluginCommand;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
-
-import com.google.common.base.Charsets;
+import com.jeff_media.updatechecker.UpdateCheckSource;
+import com.jeff_media.updatechecker.UpdateChecker;
import com.tchristofferson.configupdater.ConfigUpdater;
-
+import fr.skytasul.quests.api.Locale;
import fr.skytasul.quests.api.QuestsAPI;
import fr.skytasul.quests.api.bossbar.BQBossBarImplementation;
-import fr.skytasul.quests.commands.Commands;
import fr.skytasul.quests.commands.CommandsManager;
import fr.skytasul.quests.editors.Editor;
import fr.skytasul.quests.gui.Inventories;
@@ -44,9 +41,7 @@
import fr.skytasul.quests.gui.creation.QuestObjectGUI;
import fr.skytasul.quests.gui.creation.stages.StagesGUI;
import fr.skytasul.quests.gui.misc.ItemComparisonGUI;
-import fr.skytasul.quests.gui.quests.PlayerListGUI;
import fr.skytasul.quests.options.OptionAutoQuest;
-import fr.skytasul.quests.players.PlayerAccount;
import fr.skytasul.quests.players.PlayersManager;
import fr.skytasul.quests.players.PlayersManagerDB;
import fr.skytasul.quests.players.PlayersManagerYAML;
@@ -58,19 +53,19 @@
import fr.skytasul.quests.utils.DebugUtils;
import fr.skytasul.quests.utils.Lang;
import fr.skytasul.quests.utils.compatibility.DependenciesManager;
+import fr.skytasul.quests.utils.compatibility.Post1_16;
import fr.skytasul.quests.utils.compatibility.mobs.BukkitEntityFactory;
import fr.skytasul.quests.utils.logger.ILoggerHandler;
import fr.skytasul.quests.utils.logger.LoggerExpanded;
import fr.skytasul.quests.utils.logger.LoggerHandler;
import fr.skytasul.quests.utils.nms.NMS;
-import de.jeff_media.updatechecker.UpdateChecker;
-
public class BeautyQuests extends JavaPlugin {
public static LoggerExpanded logger;
private static BeautyQuests instance;
private BukkitRunnable saveTask;
+ private boolean isPaper;
/* --------- Storage --------- */
@@ -85,6 +80,8 @@ public class BeautyQuests extends JavaPlugin {
private File dataFile;
private File saveFolder;
+ private Path backupDir = null;
+
/* --------- Datas --------- */
private ScoreboardManager scoreboards;
@@ -99,6 +96,7 @@ public class BeautyQuests extends JavaPlugin {
public static boolean loaded = false;
public DependenciesManager dependencies = new DependenciesManager();
+ private CommandsManager command;
private LoggerHandler loggerHandler;
@@ -122,18 +120,21 @@ public void onEnable(){
try {
logger.info("------------ BeautyQuests ------------");
+ checkPaper();
+
dependencies.testCompatibilities();
Bukkit.getPluginManager().registerEvents(dependencies, this);
saveDefaultConfig();
NMS.getMCVersion();
- registerCommands();
saveFolder = new File(getDataFolder(), "quests");
if (!saveFolder.exists()) saveFolder.mkdirs();
loadDataFile();
loadConfigParameters(true);
+ registerCommands();
+
try {
dependencies.initializeCompatibilities();
}catch (Exception ex) {
@@ -156,6 +157,8 @@ public void run() {
+ (((double) System.currentTimeMillis() - lastMillis) / 1000D) + "s)!");
getServer().getPluginManager().registerEvents(new QuestsListener(), BeautyQuests.this);
+ if (NMS.getMCVersion() >= 16)
+ getServer().getPluginManager().registerEvents(new Post1_16(), BeautyQuests.this);
launchSaveCycle();
@@ -188,15 +191,30 @@ public void run() {
logger.severe("This is a fatal error. Now disabling.");
disable = true;
setEnabled(false);
+ }catch (Exception ex) {
+ logger.severe("An unexpected exception occurred while loading plugin.", ex);
+ logger.severe("This is a fatal error. Now disabling.");
+ disable = true;
+ setEnabled(false);
}
}
@Override
public void onDisable(){
try {
- Editor.leaveAll();
- Inventories.closeAll();
- stopSaveCycle();
+ try {
+ if (command != null) command.unload();
+ }catch (Throwable ex) {
+ logger.severe("An error occurred while disabling command manager.", ex);
+ }
+
+ try {
+ Editor.leaveAll();
+ Inventories.closeAll();
+ stopSaveCycle();
+ }catch (Throwable ex) {
+ logger.severe("An error occurred while disabling editing systems.", ex);
+ }
try {
if (!disable) saveAllConfig(true);
@@ -216,26 +234,21 @@ public void onDisable(){
}
/* ---------- Various init ---------- */
+
+ private void checkPaper() {
+ try {
+ isPaper = Class.forName("com.destroystokyo.paper.ParticleBuilder") != null;
+ DebugUtils.logMessage("Paper detected.");
+ }catch (ClassNotFoundException ex) {
+ isPaper = false;
+ logger.warning("You are not running the Paper software.\n"
+ + "It is highly recommended to use it for extended features and more stability.");
+ }
+ }
private void registerCommands(){
- CommandsManager questCommand = new CommandsManager((sender) -> {
- if (!(sender instanceof Player)) return;
- Player p = (Player) sender;
- if (!p.hasPermission("beautyquests.command.listPlayer")){
- Lang.INCORRECT_SYNTAX.send(p);
- }else {
- PlayerAccount acc = PlayersManager.getPlayerAccount(p);
- if (acc == null) {
- Lang.ERROR_OCCURED.send(p, "no account data");
- logger.severe("Player " + p.getName() + " has got no account. This is a CRITICAL issue.");
- }else Inventories.create(p, new PlayerListGUI(acc));
- }
- });
- PluginCommand cmd = getCommand("beautyquests");
- cmd.setPermission("beautyquests.command");
- cmd.setExecutor(questCommand);
- cmd.setTabCompleter(questCommand);
- questCommand.registerCommandsClass(new Commands());
+ command = new CommandsManager();
+ command.initializeCommands();
}
private void launchSaveCycle(){
@@ -291,31 +304,42 @@ private void launchMetrics(String pluginVersion) {
if (size > 5) return "5 - 10";
return "0 - 5";
}));
+ metrics.addCustomChart(new AdvancedPie("hooks", () -> { // replace with bar chart when bStats add them back
+ return dependencies.getDependencies()
+ .stream()
+ .filter(dep -> dep.isEnabled())
+ .map(dep -> dep.getFoundPlugin().getName())
+ .distinct()
+ .collect(Collectors.toMap(Function.identity(), __ -> 1));
+ }));
DebugUtils.logMessage("Started bStats metrics");
}
private void launchUpdateChecker(String pluginVersion) {
DebugUtils.logMessage("Starting Spigot updater");
+ UpdateChecker checker;
if (pluginVersion.contains("_")) {
Matcher matcher = Pattern.compile("_BUILD(\\d+)").matcher(pluginVersion);
if (matcher.find()) {
String build = matcher.group(1);
- UpdateChecker.init(instance, "https://ci.codemc.io/job/SkytAsul/job/BeautyQuests/lastSuccessfulBuild/buildNumber")
+ checker = new UpdateChecker(this, UpdateCheckSource.CUSTOM_URL, "https://ci.codemc.io/job/SkytAsul/job/BeautyQuests/lastSuccessfulBuild/buildNumber")
.setUserAgent("")
.setDownloadLink("https://ci.codemc.io/job/SkytAsul/job/BeautyQuests")
- .setNotifyOpsOnJoin(false)
.setUsedVersion(build)
- .setNameFreeVersion("(dev builds)")
- .checkNow();
+ .setNameFreeVersion("(dev builds)");
}else {
logger.warning("Unknown plugin version, cannot check for updates.");
+ return;
}
}else {
- UpdateChecker.init(this, 39255)
- .setDownloadLink(39255)
- .setNotifyOpsOnJoin(false)
- .checkNow();
+ checker = new UpdateChecker(this, UpdateCheckSource.SPIGOT, "39255")
+ .setDownloadLink(39255);
}
+ checker
+ .setDonationLink("https://paypal.me/SkytAsul")
+ .setSupportLink("https://discord.gg/H8fXrkD")
+ .setNotifyOpsOnJoin(false)
+ .checkNow();
}
/* ---------- YAML ---------- */
@@ -328,25 +352,25 @@ private void loadConfigParameters(boolean init) throws LoadingException {
config.getConfig().save(configFile);
logger.info("Updated config.");
}
- if (init && loadLang() == null) return;
+ if (init) loadLang();
ConfigUpdater.update(this, "config.yml", configFile);
config.init();
ConfigurationSection dbConfig = config.getConfig().getConfigurationSection("database");
if (dbConfig.getBoolean("enabled")) {
+ db = null;
try {
db = new Database(dbConfig);
db.testConnection();
logger.info("Connection to database etablished.");
}catch (Exception ex) {
- if (db != null) {
- db.closeConnection();
- db = null;
- }
+ db = null;
throw new LoadingException("Connection to database has failed.", ex);
}
}
+ PlayersManager.manager = db == null ? new PlayersManagerYAML() : new PlayersManagerDB(db);
+
/* static initialization */
if (init) {
StagesGUI.initialize(); // initializing default stage types
@@ -365,47 +389,10 @@ private void loadConfigParameters(boolean init) throws LoadingException {
private YamlConfiguration loadLang() throws LoadingException {
try {
- for (String language : new String[] { "en_US", "fr_FR", "zh_CN", "zh_HK", "de_DE", "pt_PT", "it_IT", "es_ES", "sv_SE", "hu_HU", "ru_RU", "pl_PL", "th_TH", "lt_LT", "vi_VN" }) {
- File file = new File(getDataFolder(), "locales/" + language + ".yml");
- if (!file.exists()) saveResource("locales/" + language + ".yml", false);
- }
-
- long lastMillis = System.currentTimeMillis();
loadedLanguage = config.getConfig().getString("lang", "en_US");
- String language = "locales/" + loadedLanguage + ".yml";
- File file = new File(getDataFolder(), language);
- InputStream res = getResource(language);
- boolean created = false;
- if (!file.exists()){
- logger.warning("Language file " + language + " does not exist. Using default english strings.");
- file.createNewFile();
- res = getResource("locales/en_US.yml");
- created = true;
- }
- YamlConfiguration conf = YamlConfiguration.loadConfiguration(file);
- boolean changes = false;
- if (res != null){ // if it's a local resource
- YamlConfiguration def = YamlConfiguration.loadConfiguration(new InputStreamReader(res, StandardCharsets.UTF_8));
- for (String key : def.getKeys(true)){ // get all keys in resource
- if (!def.isConfigurationSection(key)){ // if not a block
- if (!conf.contains(key)){ // if string does not exist in the file
- conf.set(key, def.get(key)); // copy string
- if (!created) DebugUtils.logMessage("String copied from source file to " + language + ". Key: " + key);
- changes = true;
- }
- }
- }
- }
- Lang.loadStrings(YamlConfiguration.loadConfiguration(new InputStreamReader(getResource("locales/en_US.yml"), Charsets.UTF_8)), conf);
-
- if (changes) {
- getLogger().info("Copied new strings into " + language + " language file.");
- conf.save(file); // if there has been changes before, save the edited file
- }
- getLogger().info("Loaded language file " + language + " (" + (((double) System.currentTimeMillis() - lastMillis) / 1000D) + "s)!");
- return conf;
- } catch(Exception e) {
- throw new LoadingException("Couldn't create language file.", e);
+ return Locale.loadLang(this, Lang.values(), loadedLanguage);
+ }catch (Exception ex) {
+ throw new LoadingException("Couldn't load language file.", ex);
}
}
@@ -426,8 +413,9 @@ private void loadDataFile() throws LoadingException {
lastVersion = data.getString("version");
if (!lastVersion.equals(getDescription().getVersion())){
logger.info("You are using a new version for the first time. (last version: " + lastVersion + ")");
- createFolderBackup();
- createDataBackup();
+ backupDir = backupDir();
+ createFolderBackup(backupDir);
+ createDataBackup(backupDir);
}
}else lastVersion = getDescription().getVersion();
data.options().header("Do not edit ANYTHING here.");
@@ -437,6 +425,7 @@ private void loadDataFile() throws LoadingException {
private void loadAllDatas() throws Throwable {
if (disable) return;
dependencies.lockDependencies();
+ command.lockCommands();
if (scoreboards == null && QuestsConfiguration.showScoreboards()) {
File scFile = new File(getDataFolder(), "scoreboard.yml");
@@ -446,10 +435,11 @@ private void loadAllDatas() throws Throwable {
}
try{
- PlayersManager.manager = db == null ? new PlayersManagerYAML() : new PlayersManagerDB(db);
+ if (db == null && backupDir != null) createPlayerDatasBackup(backupDir, (PlayersManagerYAML) PlayersManager.manager);
+
PlayersManager.manager.load();
}catch (Exception ex) {
- createDataBackup();
+ if (backupDir == null) createDataBackup(backupDir());
logger.severe("Error while loading player datas.", ex);
}
@@ -512,7 +502,6 @@ public void saveAllConfig(boolean unload) throws Exception {
try {
PlayersManager.manager.save();
}catch (Exception ex) {
- createDataBackup();
logger.severe("Error when saving player datas.", ex);
}
data.save(dataFile);
@@ -528,20 +517,27 @@ public void saveAllConfig(boolean unload) throws Exception {
private void resetDatas(){
quests = null;
pools = null;
- if (db != null) db.closeConnection();
+ try {
+ if (db != null) db.close();
+ }catch (Exception ex) {
+ logger.severe("An error occurred while closing database connection.", ex);
+ }
+ PlayersManager.manager = null;
//HandlerList.unregisterAll(this);
loaded = false;
}
/* ---------- Backups ---------- */
- public boolean createFolderBackup() {
+ public boolean createFolderBackup(Path backup) {
if (!QuestsConfiguration.backups) return false;
logger.info("Creating quests backup...");
- Path backupDir = backupDir();
+ Path backupDir = backup.resolve("quests");
Path saveFolderPath = saveFolder.toPath();
try (Stream stream = Files.walk(saveFolderPath)) {
+ Files.createDirectories(backupDir);
stream.forEach(path -> {
+ if (path.equals(saveFolderPath)) return;
try {
Files.copy(path, backupDir.resolve(saveFolderPath.relativize(path)));
}catch (IOException ex) {
@@ -556,11 +552,41 @@ public boolean createFolderBackup() {
}
}
- public boolean createDataBackup() {
+ public boolean createDataBackup(Path backup) {
if (!QuestsConfiguration.backups) return false;
logger.info("Creating data backup...");
try{
- logger.info("Datas backup created in " + Files.copy(dataFile.toPath(), backupDir().resolve("data.yml")).getParent().getFileName());
+ Path target = backup.resolve("data.yml");
+ if (Files.exists(target)) {
+ logger.warning("File " + target.toString() + " already exist. This should not happen.");
+ }else {
+ Files.createDirectories(backup);
+ logger.info("Datas backup created in " + Files.copy(dataFile.toPath(), target).getParent().getFileName());
+ }
+ return true;
+ }catch (Exception e) {
+ logger.severe("An error occured while creating the backup.", e);
+ return false;
+ }
+ }
+
+ public boolean createPlayerDatasBackup(Path backup, PlayersManagerYAML yamlManager) {
+ if (!QuestsConfiguration.backups) return false;
+
+ logger.info("Creating player datas backup...");
+ Path backupDir = backup.resolve("players");
+ Path playersFolderPath = yamlManager.getDirectory().toPath();
+ try (Stream stream = Files.walk(playersFolderPath)) {
+ Files.createDirectories(backupDir);
+ stream.forEach(path -> {
+ if (path.equals(playersFolderPath)) return;
+ try {
+ Files.copy(path, backupDir.resolve(playersFolderPath.relativize(path)));
+ }catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ });
+ logger.info("Player datas backup created in " + backupDir.getFileName().toString());
return true;
}catch (Exception e) {
logger.severe("An error occured while creating the backup.", e);
@@ -572,7 +598,12 @@ public boolean createQuestBackup(Path file, String msg) {
if (!QuestsConfiguration.backups) return false;
logger.info("Creating single quest backup...");
try{
- logger.info("Quest backup created at " + Files.copy(file, Paths.get(file.toString() + "-backup" + format.format(new Date()) + ".yml")).getFileName());
+ Path target = Paths.get(file.toString() + "-backup" + format.format(new Date()) + ".yml");
+ if (Files.exists(target)) {
+ logger.warning("File " + target.toString() + " already exist. This should not happen.");
+ }else {
+ logger.info("Quest backup created at " + Files.copy(file, target).getFileName());
+ }
return true;
}catch (Exception e) {
logger.severe("An error occured while creating the backup.", e);
@@ -582,7 +613,7 @@ public boolean createQuestBackup(Path file, String msg) {
private SimpleDateFormat format = new SimpleDateFormat("yyyy'-'MM'-'dd'-'hh'-'mm'-'ss");
- private Path backupDir() {
+ public Path backupDir() {
return getDataFolder().toPath().resolve("backup-" + format.format(new Date()));
}
@@ -624,6 +655,10 @@ public void run() {
}.runTaskLater(BeautyQuests.getInstance(), 20L);
}
+ public CommandsManager getCommand() {
+ return command;
+ }
+
public QuestsConfiguration getConfiguration() {
return config;
}
@@ -651,13 +686,17 @@ public QuestPoolsManager getPoolsManager() {
public ILoggerHandler getLoggerHandler() {
return loggerHandler == null ? ILoggerHandler.EMPTY_LOGGER : loggerHandler;
}
+
+ public boolean isRunningPaper() {
+ return isPaper;
+ }
public static BeautyQuests getInstance(){
return instance;
}
- class LoadingException extends Exception {
+ public static class LoadingException extends Exception {
private static final long serialVersionUID = -2811265488885752109L;
private String loggerMessage;
@@ -670,6 +709,11 @@ public LoadingException(String loggerMessage, Throwable cause) {
super(cause);
this.loggerMessage = loggerMessage;
}
+
+ public String getLoggerMessage() {
+ return loggerMessage;
+ }
+
}
}
diff --git a/core/src/main/java/fr/skytasul/quests/QuestsConfiguration.java b/core/src/main/java/fr/skytasul/quests/QuestsConfiguration.java
index 04190097..14195d54 100644
--- a/core/src/main/java/fr/skytasul/quests/QuestsConfiguration.java
+++ b/core/src/main/java/fr/skytasul/quests/QuestsConfiguration.java
@@ -1,10 +1,11 @@
package fr.skytasul.quests;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
-
import org.bukkit.Bukkit;
import org.bukkit.Color;
import org.bukkit.FireworkEffect;
@@ -14,14 +15,12 @@
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.FireworkMeta;
-
import com.google.common.collect.Sets;
-
import fr.skytasul.quests.api.QuestsAPI;
+import fr.skytasul.quests.api.options.description.QuestDescription;
import fr.skytasul.quests.gui.ItemUtils;
import fr.skytasul.quests.gui.quests.PlayerListGUI.Category;
import fr.skytasul.quests.structure.QuestBranch.Source;
-import fr.skytasul.quests.structure.QuestDescription;
import fr.skytasul.quests.utils.Lang;
import fr.skytasul.quests.utils.MinecraftNames;
import fr.skytasul.quests.utils.ParticleEffect;
@@ -54,13 +53,14 @@ public class QuestsConfiguration {
private static boolean mobsProgressBar = false;
private static int progressBarTimeoutSeconds = 15;
private static boolean hookAcounts = false;
+ private static boolean usePlayerBlockTracker = false;
private static ParticleEffect particleStart;
private static ParticleEffect particleTalk;
private static ParticleEffect particleNext;
private static boolean sendUpdate = true;
private static boolean stageStart = true;
private static boolean questConfirmGUI = false;
- private static ClickType npcClick = ClickType.RIGHT;
+ private static Collection npcClicks = Arrays.asList(ClickType.RIGHT, ClickType.SHIFT_RIGHT);
private static String dSetName = "Quests";
private static String dIcon = "bookshelf";
private static int dMinZoom = 0;
@@ -166,9 +166,18 @@ void init() {
mobsProgressBar = config.getBoolean("mobsProgressBar");
progressBarTimeoutSeconds = config.getInt("progressBarTimeoutSeconds");
try {
- npcClick = ClickType.valueOf(config.getString("npcClick").toUpperCase());
+ if (config.isString("npcClick")) {
+ String click = config.getString("npcClick");
+ npcClicks = Arrays.asList(click.equals("ANY") ? ClickType.values() : new ClickType[] { ClickType.valueOf(click.toUpperCase()) });
+ }else {
+ npcClicks = config.getStringList("npcClick")
+ .stream()
+ .map(String::toUpperCase)
+ .map(ClickType::valueOf)
+ .collect(Collectors.toList());
+ }
}catch (IllegalArgumentException ex) {
- BeautyQuests.logger.warning("Unknown click type " + config.getString("npcClick") + " for config entry \"npcClick\"");
+ BeautyQuests.logger.warning("Unknown click type " + config.get("npcClick") + " for config entry \"npcClick\"");
}
enablePrefix = config.getBoolean("enablePrefix");
disableTextHologram = config.getBoolean("disableTextHologram");
@@ -179,6 +188,7 @@ void init() {
Bukkit.getPluginManager().registerEvents(new Accounts(), BeautyQuests.getInstance());
BeautyQuests.logger.info("AccountsHook is now managing player datas for quests !");
}
+ usePlayerBlockTracker = DependenciesManager.PlayerBlockTracker.isEnabled() && config.getBoolean("usePlayerBlockTracker");
dSetName = config.getString("dynmap.markerSetName");
if (dSetName == null || dSetName.isEmpty()) DependenciesManager.dyn.disable();
dIcon = config.getString("dynmap.markerIcon");
@@ -305,8 +315,8 @@ public static int getProgressBarTimeout(){
return progressBarTimeoutSeconds;
}
- public static ClickType getNPCClick() {
- return npcClick;
+ public static Collection getNPCClicks() {
+ return npcClicks;
}
public static boolean handleGPS(){
@@ -417,6 +427,10 @@ public static boolean hookAccounts(){
return hookAcounts;
}
+ public static boolean usePlayerBlockTracker() {
+ return usePlayerBlockTracker;
+ }
+
public static String dynmapSetName(){
return dSetName;
}
@@ -476,10 +490,14 @@ public static QuestsMenuConfig getMenuConfig() {
}
public enum ClickType {
- RIGHT, LEFT, ANY;
+ RIGHT, SHIFT_RIGHT, LEFT, SHIFT_LEFT;
- public boolean applies(ClickType type) {
- return (this == type) || (this == ANY) || (type == ANY);
+ public static ClickType of(boolean left, boolean shift) {
+ if (left) {
+ return shift ? SHIFT_LEFT : LEFT;
+ }else {
+ return shift ? SHIFT_RIGHT : RIGHT;
+ }
}
}
diff --git a/core/src/main/java/fr/skytasul/quests/QuestsListener.java b/core/src/main/java/fr/skytasul/quests/QuestsListener.java
index 804b6896..34b3b6c7 100644
--- a/core/src/main/java/fr/skytasul/quests/QuestsListener.java
+++ b/core/src/main/java/fr/skytasul/quests/QuestsListener.java
@@ -5,14 +5,15 @@
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
-
import org.bukkit.Bukkit;
+import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
+import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.inventory.CraftItemEvent;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
@@ -22,11 +23,14 @@
import org.bukkit.event.player.PlayerItemConsumeEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
+import org.bukkit.inventory.ComplexRecipe;
import org.bukkit.inventory.ItemStack;
-
import fr.skytasul.quests.api.QuestsAPI;
import fr.skytasul.quests.api.events.BQBlockBreakEvent;
+import fr.skytasul.quests.api.events.BQCraftEvent;
import fr.skytasul.quests.api.events.BQNPCClickEvent;
+import fr.skytasul.quests.api.events.accounts.PlayerAccountJoinEvent;
+import fr.skytasul.quests.api.events.accounts.PlayerAccountLeaveEvent;
import fr.skytasul.quests.api.npcs.BQNPC;
import fr.skytasul.quests.api.options.QuestOption;
import fr.skytasul.quests.gui.Inventories;
@@ -36,21 +40,20 @@
import fr.skytasul.quests.options.OptionAutoQuest;
import fr.skytasul.quests.players.PlayerAccount;
import fr.skytasul.quests.players.PlayersManager;
-import fr.skytasul.quests.players.events.PlayerAccountJoinEvent;
-import fr.skytasul.quests.players.events.PlayerAccountLeaveEvent;
import fr.skytasul.quests.structure.Quest;
import fr.skytasul.quests.structure.pools.QuestPool;
import fr.skytasul.quests.utils.DebugUtils;
import fr.skytasul.quests.utils.Lang;
import fr.skytasul.quests.utils.Utils;
import fr.skytasul.quests.utils.XMaterial;
+import fr.skytasul.quests.utils.compatibility.Paper;
public class QuestsListener implements Listener{
@EventHandler (priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onNPCClick(BQNPCClickEvent e) {
if (e.isCancelled()) return;
- if (!QuestsConfiguration.getNPCClick().applies(e.getClick())) return;
+ if (!QuestsConfiguration.getNPCClicks().contains(e.getClick())) return;
Player p = e.getPlayer();
BQNPC npc = e.getNPC();
@@ -198,11 +201,40 @@ public void onEat(PlayerItemConsumeEvent e) {
}
}
- @EventHandler (priority = EventPriority.MONITOR)
+ @EventHandler (priority = EventPriority.HIGH)
+ public void onDeath(PlayerDeathEvent e) {
+ if (BeautyQuests.getInstance().isRunningPaper()) Paper.handleDeathItems(e, Utils::isQuestItem);
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
public void onBreak(BlockBreakEvent e) {
if (e.isCancelled()) return;
if (e.getPlayer() == null) return;
Bukkit.getPluginManager().callEvent(new BQBlockBreakEvent(e.getPlayer(), Arrays.asList(e.getBlock())));
}
+
+ @EventHandler (priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onCraftMonitor(CraftItemEvent e){
+ if (e.getInventory().getResult() == null) return;
+
+ int resultCount = e.getInventory().getResult().getAmount();
+ int materialCount = Integer.MAX_VALUE;
+
+ for (ItemStack is : e.getInventory().getMatrix())
+ if (is != null && is.getAmount() < materialCount)
+ materialCount = is.getAmount();
+
+ int maxCraftAmount = resultCount * materialCount;
+
+ ItemStack item = e.getRecipe().getResult();
+ if (item.getType() == Material.AIR && e.getRecipe() instanceof ComplexRecipe) {
+ String key = ((ComplexRecipe) e.getRecipe()).getKey().toString();
+ if (key.equals("minecraft:suspicious_stew")) {
+ item = XMaterial.SUSPICIOUS_STEW.parseItem();
+ }
+ }
+
+ Bukkit.getPluginManager().callEvent(new BQCraftEvent(e, item, maxCraftAmount));
+ }
}
diff --git a/core/src/main/java/fr/skytasul/quests/api/Locale.java b/core/src/main/java/fr/skytasul/quests/api/Locale.java
new file mode 100644
index 00000000..21ca0eb6
--- /dev/null
+++ b/core/src/main/java/fr/skytasul/quests/api/Locale.java
@@ -0,0 +1,101 @@
+package fr.skytasul.quests.api;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.util.function.Supplier;
+
+import org.bukkit.ChatColor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.plugin.Plugin;
+
+import fr.skytasul.quests.utils.ChatUtils;
+import fr.skytasul.quests.utils.DebugUtils;
+import fr.skytasul.quests.utils.Utils;
+
+public interface Locale {
+
+ String getPath();
+
+ String getValue();
+
+ void setValue(String value);
+
+ default String format(Object... replace) {
+ return Utils.format(getValue(), replace);
+ }
+
+ default String format(Supplier