From d11226d5042032513f46a08160a92994d37235d6 Mon Sep 17 00:00:00 2001 From: BONNe Date: Thu, 7 May 2020 00:19:21 +0300 Subject: [PATCH 01/20] Fixes #231 Logic issue. --- src/main/java/world/bentobox/challenges/ChallengesManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/world/bentobox/challenges/ChallengesManager.java b/src/main/java/world/bentobox/challenges/ChallengesManager.java index 26e7653..7dae64d 100644 --- a/src/main/java/world/bentobox/challenges/ChallengesManager.java +++ b/src/main/java/world/bentobox/challenges/ChallengesManager.java @@ -1526,7 +1526,7 @@ public class ChallengesManager LevelStatus lastStatus = null; for (Iterator statusIterator = this.getAllChallengeLevelStatus(user, world).iterator(); - statusIterator.hasNext() && (lastStatus == null || !lastStatus.isUnlocked());) + statusIterator.hasNext() && (lastStatus == null || lastStatus.isUnlocked());) { lastStatus = statusIterator.next(); } From 67971e44e8ebc1de87f529831a176670b819a113 Mon Sep 17 00:00:00 2001 From: BONNe Date: Thu, 7 May 2020 00:26:12 +0300 Subject: [PATCH 02/20] Fix placeholder names. Used naming scheme: [gamemode]_[addon]_[placeholder]. --- .../bentobox/challenges/ChallengesAddon.java | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/main/java/world/bentobox/challenges/ChallengesAddon.java b/src/main/java/world/bentobox/challenges/ChallengesAddon.java index e2fd286..fa38084 100644 --- a/src/main/java/world/bentobox/challenges/ChallengesAddon.java +++ b/src/main/java/world/bentobox/challenges/ChallengesAddon.java @@ -179,6 +179,9 @@ public class ChallengesAddon extends Addon { CHALLENGES_ISLAND_PROTECTION.addGameModeAddon(gameModeAddon); this.registerPlaceholders(gameModeAddon); + + // TODO: this is old placeholders. Remove when backward compatibility ends. + this.registerPlaceholdersOld(gameModeAddon); } }); @@ -320,6 +323,75 @@ public class ChallengesAddon extends Addon { * @param gameModeAddon GameMode addon where placeholders must be hooked in. */ private void registerPlaceholders(GameModeAddon gameModeAddon) + { + final String addonName = this.getDescription().getName().toLowerCase(); + final World world = gameModeAddon.getOverWorld(); + + // Number of completions for all challenges placeholder + this.getPlugin().getPlaceholdersManager().registerPlaceholder(gameModeAddon, + addonName + "_total_completion_count", + user -> String.valueOf(this.challengesManager.getTotalChallengeCompletionCount(user, world))); + + // Completed challenge count placeholder + this.getPlugin().getPlaceholdersManager().registerPlaceholder(gameModeAddon, + addonName + "_completed_count", + user -> String.valueOf(this.challengesManager.getCompletedChallengeCount(user, world))); + + // Uncompleted challenge count placeholder + this.getPlugin().getPlaceholdersManager().registerPlaceholder(gameModeAddon, + addonName + "_uncompleted_count", + user -> String.valueOf(this.challengesManager.getChallengeCount(world) - + this.challengesManager.getCompletedChallengeCount(user, world))); + + // Completed challenge level count placeholder + this.getPlugin().getPlaceholdersManager().registerPlaceholder(gameModeAddon, + addonName + "_completed_level_count", + user -> String.valueOf(this.challengesManager.getCompletedLevelCount(user, world))); + + // Uncompleted challenge level count placeholder + this.getPlugin().getPlaceholdersManager().registerPlaceholder(gameModeAddon, + addonName + "_uncompleted_level_count", + user -> String.valueOf(this.challengesManager.getLevelCount(world) - + this.challengesManager.getCompletedLevelCount(user, world))); + + // Unlocked challenge level count placeholder + this.getPlugin().getPlaceholdersManager().registerPlaceholder(gameModeAddon, + addonName + "_unlocked_level_count", + user -> String.valueOf(this.challengesManager.getLevelCount(world) - + this.challengesManager.getUnlockedLevelCount(user, world))); + + // Locked challenge level count placeholder + this.getPlugin().getPlaceholdersManager().registerPlaceholder(gameModeAddon, + addonName + "_locked_level_count", + user -> String.valueOf(this.challengesManager.getLevelCount(world) - + this.challengesManager.getUnlockedLevelCount(user, world))); + + // Latest challenge level name placeholder + this.getPlugin().getPlaceholdersManager().registerPlaceholder(gameModeAddon, + addonName + "_latest_level_name", + user -> { + ChallengeLevel level = this.challengesManager.getLatestUnlockedLevel(user, world); + return level != null ? level.getFriendlyName() : ""; + }); + + // Latest challenge level id placeholder + this.getPlugin().getPlaceholdersManager().registerPlaceholder(gameModeAddon, + addonName + "_latest_level_id", + user -> { + ChallengeLevel level = this.challengesManager.getLatestUnlockedLevel(user, world); + return level != null ? level.getUniqueId() : ""; + }); + } + + + /** + * This method registers placeholders into GameMode addon. + * @param gameModeAddon GameMode addon where placeholders must be hooked in. + * @since 0.8.1 + * @deprecated remove after 0.9.0 + */ + @Deprecated + private void registerPlaceholdersOld(GameModeAddon gameModeAddon) { final String gameMode = gameModeAddon.getDescription().getName().toLowerCase(); final World world = gameModeAddon.getOverWorld(); From ce6aa4ef55dcc3d8a78d6229d38e160202727e7d Mon Sep 17 00:00:00 2001 From: BONNe Date: Thu, 7 May 2020 19:27:59 +0300 Subject: [PATCH 03/20] Fixes #231 It should return previous level instead of current one. --- src/main/java/world/bentobox/challenges/ChallengesManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/world/bentobox/challenges/ChallengesManager.java b/src/main/java/world/bentobox/challenges/ChallengesManager.java index 7dae64d..813fc8e 100644 --- a/src/main/java/world/bentobox/challenges/ChallengesManager.java +++ b/src/main/java/world/bentobox/challenges/ChallengesManager.java @@ -1531,7 +1531,7 @@ public class ChallengesManager lastStatus = statusIterator.next(); } - return lastStatus != null ? lastStatus.getLevel() : null; + return lastStatus != null ? lastStatus.getPreviousLevel() : null; } From 1c9aa664c874d05ab9ac28878260cb66a8bac08d Mon Sep 17 00:00:00 2001 From: BONNe Date: Fri, 8 May 2020 09:38:50 +0300 Subject: [PATCH 04/20] Update to BentoBox 1.13.1. Update to Spigot 1.15.2. --- pom.xml | 4 ++-- src/main/resources/addon.yml | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 7655075..f721293 100644 --- a/pom.xml +++ b/pom.xml @@ -35,8 +35,8 @@ 1.8 2.0.2 - 1.14.4-R0.1-SNAPSHOT - 1.7.0 + 1.15.2-R0.1-SNAPSHOT + 1.13.1 1.6.0 1.7 diff --git a/src/main/resources/addon.yml b/src/main/resources/addon.yml index cdbe733..2a96852 100755 --- a/src/main/resources/addon.yml +++ b/src/main/resources/addon.yml @@ -1,6 +1,7 @@ name: Challenges main: world.bentobox.challenges.ChallengesAddon version: ${version}${build.number} +api-version: 1.13.1 repository: 'BentoBoxWorld/Challenges' metrics: true From e32799a1fbfab8555ea25b5fc797739567419ebd Mon Sep 17 00:00:00 2001 From: BONNe Date: Fri, 8 May 2020 09:40:13 +0300 Subject: [PATCH 05/20] Fix config issues. Populate challenge lore and level lore with all enum values on initialization, instead of leaving them empty. Fix wrong message about reset for some config options. --- .../world/bentobox/challenges/config/Settings.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/world/bentobox/challenges/config/Settings.java b/src/main/java/world/bentobox/challenges/config/Settings.java index 49df416..2332b46 100644 --- a/src/main/java/world/bentobox/challenges/config/Settings.java +++ b/src/main/java/world/bentobox/challenges/config/Settings.java @@ -1,7 +1,7 @@ package world.bentobox.challenges.config; -import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -34,14 +34,14 @@ public class Settings implements ConfigObject @ConfigComment("Allows to define common challenges command that will open User GUI") @ConfigComment("with all GameMode selection or Challenges from user world.") @ConfigComment("This will not affect /{gamemode_user} challenges command.") - @ConfigEntry(path = "commands.user", needsReset = true) + @ConfigEntry(path = "commands.user", needsRestart = true) private String userCommand = "challenges c"; @ConfigComment("") @ConfigComment("Allows to define common challenges command that will open Admin GUI") @ConfigComment("with all GameMode selection.") @ConfigComment("This will not affect /{gamemode_admin} challenges command.") - @ConfigEntry(path = "commands.admin", needsReset = true) + @ConfigEntry(path = "commands.admin", needsRestart = true) private String adminCommand = "challengesadmin chadmin"; @ConfigComment("") @@ -49,7 +49,7 @@ public class Settings implements ConfigObject @ConfigComment("all GameModes. For admins it will open selection with all GameModes") @ConfigComment("(unless there is one), but for users it will open GUI that corresponds") @ConfigComment("to their world (unless it is specified other way in Admin GUI).") - @ConfigEntry(path = "commands.single-gui", needsReset = true) + @ConfigEntry(path = "commands.single-gui", needsRestart = true) private boolean useCommonGUI = false; @ConfigComment("") @@ -130,7 +130,7 @@ public class Settings implements ConfigObject @ConfigComment("Requirement and reward items, blocks and entities that are defined in challenge and can be customized under 'challenges.gui.item-description.*'") @ConfigEntry(path = "gui-settings.challenge-lore") @Adapter(ChallengeLoreAdapter.class) - private List challengeLoreMessage = new ArrayList<>(); + private List challengeLoreMessage = Arrays.asList(ChallengeLore.values()); @ConfigComment("") @ConfigComment("This string allows to change element order in Level description. Each letter represents") @@ -149,7 +149,7 @@ public class Settings implements ConfigObject @ConfigComment("Reward items that are defined in challenge level and can be customized under 'challenges.gui.item-description.*'") @ConfigEntry(path = "gui-settings.level-lore") @Adapter(LevelLoreAdapter.class) - private List levelLoreMessage = new ArrayList<>(); + private List levelLoreMessage = Arrays.asList(LevelLore.values()); @ConfigComment("") @ConfigComment("This indicate if challenges data will be stored per island (true) or per player (false).") From fdafce0b863a4712f8287cf13ec4f80da4726b12 Mon Sep 17 00:00:00 2001 From: BONNe Date: Fri, 8 May 2020 09:48:07 +0300 Subject: [PATCH 06/20] Add bee head in HeadLib --- src/main/java/world/bentobox/challenges/utils/HeadLib.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/world/bentobox/challenges/utils/HeadLib.java b/src/main/java/world/bentobox/challenges/utils/HeadLib.java index 1bbae6a..066f75b 100644 --- a/src/main/java/world/bentobox/challenges/utils/HeadLib.java +++ b/src/main/java/world/bentobox/challenges/utils/HeadLib.java @@ -111,7 +111,9 @@ public enum HeadLib PILLAGER("1ac9d5aa-46ef-4d71-b077-4564382c0a43", "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNGFlZTZiYjM3Y2JmYzkyYjBkODZkYjVhZGE0NzkwYzY0ZmY0NDY4ZDY4Yjg0OTQyZmRlMDQ0MDVlOGVmNTMzMyJ9fX0="), RAVAGER("def81bd7-85e5-4644-b1b2-e7521e53bba8", "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWNiOWYxMzlmOTQ4OWQ4NmU0MTBhMDZkOGNiYzY3MGM4MDI4MTM3NTA4ZTNlNGJlZjYxMmZlMzJlZGQ2MDE5MyJ9fX0="), TRADER_LLAMA("47dbdab5-105f-42bc-9580-c61cee9231f3", "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzA4N2E1NTZkNGZmYTk1ZWNkMjg0NGYzNTBkYzQzZTI1NGU1ZDUzNWZhNTk2ZjU0MGQ3ZTc3ZmE2N2RmNDY5NiJ9fX0="), - WANDERING_TRADER("943947ea-3e1a-4fdc-85e5-f538379f05e9", "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWYxMzc5YTgyMjkwZDdhYmUxZWZhYWJiYzcwNzEwZmYyZWMwMmRkMzRhZGUzODZiYzAwYzkzMGM0NjFjZjkzMiJ9fX0="); + WANDERING_TRADER("943947ea-3e1a-4fdc-85e5-f538379f05e9", "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWYxMzc5YTgyMjkwZDdhYmUxZWZhYWJiYzcwNzEwZmYyZWMwMmRkMzRhZGUzODZiYzAwYzkzMGM0NjFjZjkzMiJ9fX0="), + // Since 1.15 + BEE("77342662-8870-445a-869f-f0aef1406b3d", "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTlhYzE2ZjI5NmI0NjFkMDVlYTA3ODVkNDc3MDMzZTUyNzM1OGI0ZjMwYzI2NmFhMDJmMDIwMTU3ZmZjYTczNiJ9fX0="); // --------------------------------------------------------------------- From ffac90f84c2bf93140bb535571cc4a837c17b2fc Mon Sep 17 00:00:00 2001 From: BONNe Date: Fri, 8 May 2020 10:20:01 +0300 Subject: [PATCH 07/20] Add NULL protection in challenge and level loading. Remove Challenge and Level saving on server stop, as it is done in GUI after editing. Reduce load on database. Use saveAsync, as saveObject is deprecated. --- .../challenges/ChallengesManager.java | 60 ++++++++++++++----- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/src/main/java/world/bentobox/challenges/ChallengesManager.java b/src/main/java/world/bentobox/challenges/ChallengesManager.java index 813fc8e..c2e8af1 100644 --- a/src/main/java/world/bentobox/challenges/ChallengesManager.java +++ b/src/main/java/world/bentobox/challenges/ChallengesManager.java @@ -206,11 +206,15 @@ public class ChallengesManager } this.playerCacheData.clear(); - loadAndValidate(); + this.loadAndValidate(); } - private void loadAndValidate() { + /** + * This method loads and validates all challenges and levels. + */ + private void loadAndValidate() + { this.challengeDatabase.loadObjects().forEach(this::loadChallenge); this.levelDatabase.loadObjects().forEach(this::loadLevel); // this validate challenge levels @@ -233,7 +237,7 @@ public class ChallengesManager //this.levelDatabase = new Database<>(addon, ChallengeLevel.class); //this.playersDatabase = new Database<>(addon, ChallengesPlayerData.class); - loadAndValidate(); + this.loadAndValidate(); } @@ -263,6 +267,18 @@ public class ChallengesManager User user, boolean silent) { + // This may happen if database somehow failed to load challenge and return + // null as input. + if (challenge == null) + { + if (!silent) + { + user.sendMessage("load-error", "[value]", "NULL"); + } + + return false; + } + if (this.challengeCacheData.containsKey(challenge.getUniqueId())) { if (!overwrite) @@ -324,6 +340,18 @@ public class ChallengesManager User user, boolean silent) { + // This may happen if database somehow failed to load challenge and return + // null as input. + if (level == null) + { + if (!silent) + { + user.sendMessage("load-error", "[value]", "NULL"); + } + + return false; + } + if (!this.isValidLevel(level)) { if (user != null) @@ -474,11 +502,8 @@ public class ChallengesManager { if (!this.challengeCacheData.containsKey(uniqueID)) { - if (this.challengeDatabase.objectExists(uniqueID)) - { - this.loadChallenge(this.challengeDatabase.loadObject(uniqueID)); - } - else + if (!this.challengeDatabase.objectExists(uniqueID) || + !this.loadChallenge(this.challengeDatabase.loadObject(uniqueID), false, null, true)) { this.addon.logError("Cannot find " + uniqueID + " challenge for " + level.getUniqueId()); return false; @@ -824,8 +849,11 @@ public class ChallengesManager */ public void save() { - this.saveChallenges(); - this.saveLevels(); + // Challenges and Levels are saved on modifications only to avoid issues with + // NULL's in data after interrupting server while in saving stage. + // this.saveChallenges(); + // this.saveLevels(); + this.savePlayersData(); } @@ -835,7 +863,7 @@ public class ChallengesManager */ private void saveChallenges() { - this.challengeCacheData.values().forEach(this.challengeDatabase::saveObject); + this.challengeCacheData.values().forEach(this::saveChallenge); } @@ -845,7 +873,7 @@ public class ChallengesManager */ public void saveChallenge(Challenge challenge) { - this.challengeDatabase.saveObject(challenge); + this.challengeDatabase.saveObjectAsync(challenge); } @@ -854,7 +882,7 @@ public class ChallengesManager */ private void saveLevels() { - this.levelCacheData.values().forEach(this.levelDatabase::saveObject); + this.levelCacheData.values().forEach(this::saveLevel); } @@ -864,7 +892,7 @@ public class ChallengesManager */ public void saveLevel(ChallengeLevel level) { - this.levelDatabase.saveObject(level); + this.levelDatabase.saveObjectAsync(level); } @@ -873,7 +901,7 @@ public class ChallengesManager */ private void savePlayersData() { - this.playerCacheData.values().forEach(this.playersDatabase::saveObject); + this.playerCacheData.values().forEach(this.playersDatabase::saveObjectAsync); } @@ -902,7 +930,7 @@ public class ChallengesManager } } - this.playersDatabase.saveObject(cachedData); + this.playersDatabase.saveObjectAsync(cachedData); } } From da5fab855886a02fe4f94364e8a437f9d0d601a2 Mon Sep 17 00:00:00 2001 From: BONNe Date: Fri, 8 May 2020 10:20:44 +0300 Subject: [PATCH 08/20] Remove settings saving on addon disabling. Settings are saved on each Settings GUI building. --- .../java/world/bentobox/challenges/ChallengesAddon.java | 7 +++++++ .../bentobox/challenges/panel/admin/EditSettingsGUI.java | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/src/main/java/world/bentobox/challenges/ChallengesAddon.java b/src/main/java/world/bentobox/challenges/ChallengesAddon.java index fa38084..69daafa 100644 --- a/src/main/java/world/bentobox/challenges/ChallengesAddon.java +++ b/src/main/java/world/bentobox/challenges/ChallengesAddon.java @@ -286,7 +286,14 @@ public class ChallengesAddon extends Addon { if (this.hooked) { this.challengesManager.save(); } + } + + /** + * This method saves addon settings into file. + */ + public void saveSettings() + { if (this.settings != null) { new Config<>(this, Settings.class).saveConfigObject(this.settings); diff --git a/src/main/java/world/bentobox/challenges/panel/admin/EditSettingsGUI.java b/src/main/java/world/bentobox/challenges/panel/admin/EditSettingsGUI.java index 40abf68..c808dac 100644 --- a/src/main/java/world/bentobox/challenges/panel/admin/EditSettingsGUI.java +++ b/src/main/java/world/bentobox/challenges/panel/admin/EditSettingsGUI.java @@ -124,6 +124,10 @@ public class EditSettingsGUI extends CommonGUI // Return Button panelBuilder.item(44, this.returnButton); + // Save Settings every time this GUI is created. It will avoid issues with + // Overwritten setting after server stop. + this.addon.saveSettings(); + panelBuilder.build(); } From 6203b92f2e9f067fc13f86d7073d90623ef91e96 Mon Sep 17 00:00:00 2001 From: tastybento Date: Sat, 9 May 2020 12:51:13 -0700 Subject: [PATCH 09/20] Fixed tests. --- .../java/world/bentobox/challenges/ChallengesManagerTest.java | 1 + .../java/world/bentobox/challenges/tasks/TryToCompleteTest.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/world/bentobox/challenges/ChallengesManagerTest.java b/src/test/java/world/bentobox/challenges/ChallengesManagerTest.java index bbe3b8e..d9aa352 100644 --- a/src/test/java/world/bentobox/challenges/ChallengesManagerTest.java +++ b/src/test/java/world/bentobox/challenges/ChallengesManagerTest.java @@ -118,6 +118,7 @@ public class ChallengesManagerTest { BentoBox plugin = mock(BentoBox.class); Whitebox.setInternalState(BentoBox.class, "instance", plugin); when(addon.getPlugin()).thenReturn(plugin); + User.setPlugin(plugin); // IWM when(plugin.getIWM()).thenReturn(iwm); diff --git a/src/test/java/world/bentobox/challenges/tasks/TryToCompleteTest.java b/src/test/java/world/bentobox/challenges/tasks/TryToCompleteTest.java index 9f72b31..2bbbe26 100644 --- a/src/test/java/world/bentobox/challenges/tasks/TryToCompleteTest.java +++ b/src/test/java/world/bentobox/challenges/tasks/TryToCompleteTest.java @@ -167,6 +167,7 @@ public class TryToCompleteTest { PowerMockito.mockStatic(Util.class); when(Util.getWorld(any())).thenReturn(world); when(Util.prettifyText(anyString())).thenCallRealMethod(); + when(Util.stripSpaceAfterColorCodes(anyString())).thenCallRealMethod(); // Island World Manager IslandWorldManager iwm = mock(IslandWorldManager.class); @@ -252,7 +253,6 @@ public class TryToCompleteTest { // ItemFactory ItemFactory itemFactory = mock(ItemFactory.class); when(Bukkit.getItemFactory()).thenReturn(itemFactory); - } /** From 679fe488711b2da066fddcd976991fc009206a68 Mon Sep 17 00:00:00 2001 From: BONNe Date: Tue, 26 May 2020 10:19:32 +0300 Subject: [PATCH 10/20] Fix issue when challenges are not saved in database after importing from web or default file set. --- .../world/bentobox/challenges/ChallengesImportManager.java | 6 ++++-- .../java/world/bentobox/challenges/ChallengesManager.java | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/world/bentobox/challenges/ChallengesImportManager.java b/src/main/java/world/bentobox/challenges/ChallengesImportManager.java index e0feb65..36b5655 100644 --- a/src/main/java/world/bentobox/challenges/ChallengesImportManager.java +++ b/src/main/java/world/bentobox/challenges/ChallengesImportManager.java @@ -126,7 +126,8 @@ public class ChallengesImportManager return false; } - this.addon.getChallengesManager().save(); + this.addon.getChallengesManager().saveChallenges(); + this.addon.getChallengesManager().saveLevels(); if (removeAtEnd) { @@ -203,7 +204,8 @@ public class ChallengesImportManager return false; } - this.addon.getChallengesManager().save(); + this.addon.getChallengesManager().saveChallenges(); + this.addon.getChallengesManager().saveLevels(); return true; } diff --git a/src/main/java/world/bentobox/challenges/ChallengesManager.java b/src/main/java/world/bentobox/challenges/ChallengesManager.java index c2e8af1..e3e72db 100644 --- a/src/main/java/world/bentobox/challenges/ChallengesManager.java +++ b/src/main/java/world/bentobox/challenges/ChallengesManager.java @@ -861,7 +861,7 @@ public class ChallengesManager /** * This method saves all challenges to database. */ - private void saveChallenges() + public void saveChallenges() { this.challengeCacheData.values().forEach(this::saveChallenge); } @@ -880,7 +880,7 @@ public class ChallengesManager /** * This method saves all levels to database. */ - private void saveLevels() + public void saveLevels() { this.levelCacheData.values().forEach(this::saveLevel); } From dd8834f1df0e3a5d938b79efeab233293a5f481b Mon Sep 17 00:00:00 2001 From: BONNe Date: Wed, 17 Jun 2020 08:32:15 +0300 Subject: [PATCH 11/20] Fixes #243 Challenges level status for unlocking should look on previous level waiver amount, not on its value. Also, if second level is marked as locked, then all next levels should also be marked as locked. --- .../world/bentobox/challenges/ChallengesManager.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/world/bentobox/challenges/ChallengesManager.java b/src/main/java/world/bentobox/challenges/ChallengesManager.java index e3e72db..571bed7 100644 --- a/src/main/java/world/bentobox/challenges/ChallengesManager.java +++ b/src/main/java/world/bentobox/challenges/ChallengesManager.java @@ -1107,6 +1107,7 @@ public class ChallengesManager // The first level is always unlocked and previous for it is null. ChallengeLevel previousLevel = null; int doneChallengeCount = 0; + boolean previousUnlocked = true; // For each challenge level, check how many the storageDataID has done for (ChallengeLevel level : challengeLevelList) @@ -1116,20 +1117,25 @@ public class ChallengesManager // remove waiver amount to get count of challenges that still necessary to do. int challengesToDo = previousLevel == null ? 0 : - (previousLevel.getChallenges().size() - doneChallengeCount - level.getWaiverAmount()); + (previousLevel.getChallenges().size() - doneChallengeCount - previousLevel.getWaiverAmount()); // As level already contains unique ids of challenges, just iterate through them. doneChallengeCount = (int) level.getChallenges().stream().filter(playerData::isChallengeDone).count(); + // Mark if level is unlocked + boolean unlocked = previousUnlocked && challengesToDo <= 0; + result.add(new LevelStatus( level, previousLevel, challengesToDo, level.getChallenges().size() == doneChallengeCount, - challengesToDo <= 0)); + unlocked)); previousLevel = level; + previousUnlocked = unlocked; } + return result; } @@ -1160,7 +1166,7 @@ public class ChallengesManager ChallengeLevel previousLevel = levelIndex < 1 ? null : challengeLevelList.get(levelIndex - 1); int challengesToDo = previousLevel == null ? 0 : - (previousLevel.getChallenges().size() - level.getWaiverAmount()) - + (previousLevel.getChallenges().size() - previousLevel.getWaiverAmount()) - (int) previousLevel.getChallenges().stream().filter(playerData::isChallengeDone).count(); // As level already contains unique ids of challenges, just iterate through them. From e85b687e362ff11b972f2a3391e4411e94595709 Mon Sep 17 00:00:00 2001 From: BONNe Date: Fri, 19 Jun 2020 11:36:26 +0300 Subject: [PATCH 12/20] Fixes #244 Implement 2 new placeholders. --- .../bentobox/challenges/ChallengesAddon.java | 18 ++++++++++++++++++ .../bentobox/challenges/ChallengesManager.java | 15 +++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/main/java/world/bentobox/challenges/ChallengesAddon.java b/src/main/java/world/bentobox/challenges/ChallengesAddon.java index 69daafa..8436dc5 100644 --- a/src/main/java/world/bentobox/challenges/ChallengesAddon.java +++ b/src/main/java/world/bentobox/challenges/ChallengesAddon.java @@ -388,6 +388,24 @@ public class ChallengesAddon extends Addon { ChallengeLevel level = this.challengesManager.getLatestUnlockedLevel(user, world); return level != null ? level.getUniqueId() : ""; }); + + // Completed challenge count in latest level + this.getPlugin().getPlaceholdersManager().registerPlaceholder(gameModeAddon, + addonName + "_latest_level_completed_count", + user -> { + ChallengeLevel level = this.challengesManager.getLatestUnlockedLevel(user, world); + return String.valueOf(level != null ? + this.challengesManager.getLevelCompletedChallengeCount(user, world, level) : 0); + }); + + // Uncompleted challenge count in latest level + this.getPlugin().getPlaceholdersManager().registerPlaceholder(gameModeAddon, + addonName + "_latest_level_uncompleted_count", + user -> { + ChallengeLevel level = this.challengesManager.getLatestUnlockedLevel(user, world); + return String.valueOf(level != null ? + level.getChallenges().size() - this.challengesManager.getLevelCompletedChallengeCount(user, world, level) : 0); + }); } diff --git a/src/main/java/world/bentobox/challenges/ChallengesManager.java b/src/main/java/world/bentobox/challenges/ChallengesManager.java index 571bed7..522b61c 100644 --- a/src/main/java/world/bentobox/challenges/ChallengesManager.java +++ b/src/main/java/world/bentobox/challenges/ChallengesManager.java @@ -1786,6 +1786,21 @@ public class ChallengesManager } + /** + * This method returns completed challenge count in given level. + * @param user User which should be checked + * @param world World where challenges are operating + * @param level Level which challenges must be checked. + * @return Number of completed challenges in given level. + */ + public long getLevelCompletedChallengeCount(User user, World world, ChallengeLevel level) + { + return this.getLevelChallenges(level).stream(). + filter(challenge -> this.getChallengeTimes(user, world, challenge) > 0). + count(); + } + + // --------------------------------------------------------------------- // Section: Level related methods // --------------------------------------------------------------------- From ce14c20126ff311a115b6a462de48246d4c1fc19 Mon Sep 17 00:00:00 2001 From: BONNe Date: Tue, 7 Jul 2020 11:58:09 +0300 Subject: [PATCH 13/20] Update to BentoBox 1.14-SNAPSHOT API. Implement new API features. Replace deprecated methods. Add compatibility layer with Minecraft 1.16 version. --- pom.xml | 2 +- .../challenges/ChallengesManager.java | 10 +- .../challenges/database/object/Challenge.java | 4 + .../database/object/ChallengeLevel.java | 2 + .../database/object/ChallengesPlayerData.java | 2 + .../adapters/EntityCompatibilityAdapter.java | 92 +++++++++++++++++++ .../requirements/IslandRequirements.java | 4 + src/main/resources/addon.yml | 50 +--------- 8 files changed, 115 insertions(+), 51 deletions(-) create mode 100644 src/main/java/world/bentobox/challenges/database/object/adapters/EntityCompatibilityAdapter.java diff --git a/pom.xml b/pom.xml index f721293..ac80278 100644 --- a/pom.xml +++ b/pom.xml @@ -36,7 +36,7 @@ 2.0.2 1.15.2-R0.1-SNAPSHOT - 1.13.1 + 1.14.0-SNAPSHOT 1.6.0 1.7 diff --git a/src/main/java/world/bentobox/challenges/ChallengesManager.java b/src/main/java/world/bentobox/challenges/ChallengesManager.java index 522b61c..f522c67 100644 --- a/src/main/java/world/bentobox/challenges/ChallengesManager.java +++ b/src/main/java/world/bentobox/challenges/ChallengesManager.java @@ -549,7 +549,7 @@ public class ChallengesManager { // Create the player data ChallengesPlayerData pd = new ChallengesPlayerData(uniqueID); - this.playersDatabase.saveObject(pd); + this.playersDatabase.saveObjectAsync(pd); // Add to cache this.playerCacheData.put(uniqueID, pd); } @@ -696,7 +696,7 @@ public class ChallengesManager challengesID.forEach(challenge -> level.getChallenges().add(addonName + challenge.substring(world.getName().length()))); - this.levelDatabase.saveObject(level); + this.levelDatabase.saveObjectAsync(level); this.levelCacheData.put(level.getUniqueId(), level); updated = true; @@ -740,7 +740,7 @@ public class ChallengesManager updated = true; - this.challengeDatabase.saveObject(challenge); + this.challengeDatabase.saveObjectAsync(challenge); this.challengeCacheData.put(challenge.getUniqueId(), challenge); } @@ -783,7 +783,7 @@ public class ChallengesManager // This save should not involve any upgrades in other parts. - this.challengeDatabase.saveObject(challenge); + this.challengeDatabase.saveObjectAsync(challenge); this.challengeCacheData.put(challenge.getUniqueId(), challenge); } } @@ -834,7 +834,7 @@ public class ChallengesManager } }); - this.playersDatabase.saveObject(playerData); + this.playersDatabase.saveObjectAsync(playerData); }); } diff --git a/src/main/java/world/bentobox/challenges/database/object/Challenge.java b/src/main/java/world/bentobox/challenges/database/object/Challenge.java index cff291f..a8990cc 100644 --- a/src/main/java/world/bentobox/challenges/database/object/Challenge.java +++ b/src/main/java/world/bentobox/challenges/database/object/Challenge.java @@ -19,6 +19,8 @@ import com.google.gson.annotations.Expose; import com.google.gson.annotations.JsonAdapter; import world.bentobox.bentobox.database.objects.DataObject; +import world.bentobox.bentobox.database.objects.Table; +import world.bentobox.challenges.database.object.adapters.EntityCompatibilityAdapter; import world.bentobox.challenges.database.object.adapters.RequirementsAdapter; import world.bentobox.challenges.database.object.requirements.Requirements; @@ -28,6 +30,7 @@ import world.bentobox.challenges.database.object.requirements.Requirements; * @author tastybento * */ +@Table(name = "Challenge") public class Challenge implements DataObject { /** @@ -156,6 +159,7 @@ public class Challenge implements DataObject @Deprecated @Expose + @JsonAdapter(EntityCompatibilityAdapter.class) private Map requiredEntities = new EnumMap<>(EntityType.class); @Deprecated diff --git a/src/main/java/world/bentobox/challenges/database/object/ChallengeLevel.java b/src/main/java/world/bentobox/challenges/database/object/ChallengeLevel.java index 7fb26bf..63c108d 100644 --- a/src/main/java/world/bentobox/challenges/database/object/ChallengeLevel.java +++ b/src/main/java/world/bentobox/challenges/database/object/ChallengeLevel.java @@ -14,6 +14,7 @@ import com.google.gson.annotations.Expose; import world.bentobox.bentobox.api.configuration.ConfigComment; import world.bentobox.bentobox.database.objects.DataObject; +import world.bentobox.bentobox.database.objects.Table; import world.bentobox.challenges.ChallengesManager; /** @@ -21,6 +22,7 @@ import world.bentobox.challenges.ChallengesManager; * @author tastybento * */ +@Table(name = "ChallengeLevel") public class ChallengeLevel implements DataObject, Comparable { /** diff --git a/src/main/java/world/bentobox/challenges/database/object/ChallengesPlayerData.java b/src/main/java/world/bentobox/challenges/database/object/ChallengesPlayerData.java index db306a9..c1de447 100644 --- a/src/main/java/world/bentobox/challenges/database/object/ChallengesPlayerData.java +++ b/src/main/java/world/bentobox/challenges/database/object/ChallengesPlayerData.java @@ -14,6 +14,7 @@ import com.google.gson.annotations.Expose; import world.bentobox.bentobox.api.logs.LogEntry; import world.bentobox.bentobox.database.objects.DataObject; +import world.bentobox.bentobox.database.objects.Table; import world.bentobox.bentobox.database.objects.adapters.Adapter; import world.bentobox.bentobox.database.objects.adapters.LogEntryListAdapter; @@ -23,6 +24,7 @@ import world.bentobox.bentobox.database.objects.adapters.LogEntryListAdapter; * @author tastybento * */ +@Table(name = "ChallengesPlayerData") public class ChallengesPlayerData implements DataObject { /** diff --git a/src/main/java/world/bentobox/challenges/database/object/adapters/EntityCompatibilityAdapter.java b/src/main/java/world/bentobox/challenges/database/object/adapters/EntityCompatibilityAdapter.java new file mode 100644 index 0000000..b64a32f --- /dev/null +++ b/src/main/java/world/bentobox/challenges/database/object/adapters/EntityCompatibilityAdapter.java @@ -0,0 +1,92 @@ +// +// Created by BONNe +// Copyright - 2020 +// + + +package world.bentobox.challenges.database.object.adapters; + + +import com.google.gson.*; +import org.bukkit.entity.EntityType; +import java.lang.reflect.Type; +import java.util.EnumMap; +import java.util.Map; + +import world.bentobox.bentobox.BentoBox; + + +/** + * This is compatibility class for dealing with Mojang renamed entities. + * Created for update 1.16. + */ +public class EntityCompatibilityAdapter implements + JsonSerializer>, JsonDeserializer> +{ + /** + * This method serializes input map as String Key and Integer value. + * @param src EnumMap that contains EntityType as key and Integer as value. + * @return serialized JsonElement. + */ + @Override + public JsonElement serialize(Map src, Type typeOfSrc, JsonSerializationContext context) + { + JsonObject jsonArray = new JsonObject(); + + src.forEach((entity, number) -> + { + jsonArray.addProperty(entity.name(), number); + }); + + return jsonArray; + } + + + /** + * This method deserializes json object that stores Entity Name and amount as integer. + * @param json Json element that must be parsed. + * @return EnumMap that contains EntityType as key and Integer as value. + * @throws JsonParseException + */ + @Override + public Map deserialize(JsonElement json, + Type typeOfT, + JsonDeserializationContext context) + throws JsonParseException + { + Map map = new EnumMap<>(EntityType.class); + + for (Map.Entry entrySet : json.getAsJsonObject().entrySet()) + { + try + { + EntityType entityType = EntityType.valueOf(entrySet.getKey()); + map.put(entityType, entrySet.getValue().getAsInt()); + } + catch (IllegalArgumentException e) + { + if (entrySet.getKey().equals("PIG_ZOMBIE")) + { + // Hacky way how to get new entity name. + map.put(EntityType.valueOf("ZOMBIFIED_PIGLIN"), + entrySet.getValue().getAsInt()); + } + else if (entrySet.getKey().equals("ZOMBIFIED_PIGLIN")) + { + // Hacky way how to get new entity name. + map.put(EntityType.valueOf("PIG_ZOMBIE"), + entrySet.getValue().getAsInt()); + } + else + { + // No replacement for new entities in older server. + BentoBox.getInstance().logWarning("[ChallengesAddon] Entity with name `" + + entrySet.getKey() + "` does not exist in your Minecraft server version." + + " It will be skipped!"); + } + } + } + + return map; + } +} \ No newline at end of file diff --git a/src/main/java/world/bentobox/challenges/database/object/requirements/IslandRequirements.java b/src/main/java/world/bentobox/challenges/database/object/requirements/IslandRequirements.java index dac9ab4..196c8a6 100644 --- a/src/main/java/world/bentobox/challenges/database/object/requirements/IslandRequirements.java +++ b/src/main/java/world/bentobox/challenges/database/object/requirements/IslandRequirements.java @@ -16,6 +16,9 @@ import org.bukkit.Material; import org.bukkit.entity.EntityType; import com.google.gson.annotations.Expose; +import com.google.gson.annotations.JsonAdapter; + +import world.bentobox.challenges.database.object.adapters.EntityCompatibilityAdapter; /** @@ -193,6 +196,7 @@ public class IslandRequirements extends Requirements * Map that contains which entities and how many is necessary around player to complete challenge. */ @Expose + @JsonAdapter(EntityCompatibilityAdapter.class) private Map requiredEntities = new EnumMap<>(EntityType.class); /** diff --git a/src/main/resources/addon.yml b/src/main/resources/addon.yml index 2a96852..c43b240 100755 --- a/src/main/resources/addon.yml +++ b/src/main/resources/addon.yml @@ -1,7 +1,7 @@ name: Challenges main: world.bentobox.challenges.ChallengesAddon version: ${version}${build.number} -api-version: 1.13.1 +api-version: 1.14 repository: 'BentoBoxWorld/Challenges' metrics: true @@ -19,52 +19,12 @@ permissions: description: Let the player use the '/challenges' command default: true - bskyblock.challenges: + '[gamemode].challenges': description: Let the player use the '/island challenges' command default: true - bskyblock.challenges.multiple: + '[gamemode].challenges.multiple': description: Let the player complete challenge multiple times default: true - bskyblock.admin.challenges: + '[gamemode].admin.challenges': description: Access challenge admin commands - default: op - - acidisland.challenges: - description: Let the player use the '/ai challenges' command - default: true - acidisland.challenges.multiple: - description: Let the player complete challenge multiple times - default: true - acidisland.admin.challenges: - description: Access challenge admin commands - default: op - - caveblock.challenges: - description: Let the player use the '/cave challenges' command - default: true - caveblock.challenges.multiple: - description: Let the player complete challenge multiple times - default: true - caveblock.admin.challenges: - description: Access challenge admin commands - default: op - - skygrid.challenges: - description: Let the player use the '/skygrid challenges' command - default: true - skygrid.challenges.multiple: - description: Let the player complete challenge multiple times - default: true - skygrid.admin.challenges: - description: Access challenge admin commands - default: op - - aoneblock.challenges: - description: Let the player use the '/aoneblock challenges' command - default: true - aoneblock.challenges.multiple: - description: Let the player complete challenge multiple times - default: true - aoneblock.admin.challenges: - description: Access challenge admin commands - default: op + default: op \ No newline at end of file From 129f6920456b44baacfcbf91f1e6920c18b4646e Mon Sep 17 00:00:00 2001 From: BONNe Date: Wed, 8 Jul 2020 09:56:55 +0300 Subject: [PATCH 14/20] Comment out code that removes player from local cache on leaving server. It is done due #246 reported that relog could be done faster than async saving. --- .../bentobox/challenges/ChallengesManager.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/world/bentobox/challenges/ChallengesManager.java b/src/main/java/world/bentobox/challenges/ChallengesManager.java index f522c67..28a7c70 100644 --- a/src/main/java/world/bentobox/challenges/ChallengesManager.java +++ b/src/main/java/world/bentobox/challenges/ChallengesManager.java @@ -430,12 +430,15 @@ public class ChallengesManager */ public void removeFromCache(UUID playerID) { - if (!this.settings.isStoreAsIslandData() && this.playerCacheData.containsKey(playerID.toString())) - { - // save before remove - this.savePlayerData(playerID.toString()); - this.playerCacheData.remove(playerID.toString()); - } +// Remove due possible issues with saving... (#246) +// if (!this.settings.isStoreAsIslandData() && this.playerCacheData.containsKey(playerID.toString())) +// { +// // save before remove +// this.savePlayerData(playerID.toString()); +// this.playerCacheData.remove(playerID.toString()); +// } + + this.savePlayerData(playerID.toString()); // TODO: It would be necessary to remove also data, if they stores islands. // Unfortunately, I do not know all worlds. Checking everything would be bad. Probably, I could From fcb763407904f1fc1682ad479bc70975bc7d985e Mon Sep 17 00:00:00 2001 From: BONNe Date: Thu, 9 Jul 2020 22:45:23 +0300 Subject: [PATCH 15/20] Downgrade to 0.8.3 version. Added 1.16 entities to HeadLib. Update to released BentoBox version. --- pom.xml | 4 ++-- .../java/world/bentobox/challenges/utils/HeadLib.java | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index ac80278..ca3beb8 100644 --- a/pom.xml +++ b/pom.xml @@ -36,13 +36,13 @@ 2.0.2 1.15.2-R0.1-SNAPSHOT - 1.14.0-SNAPSHOT + 1.14.0 1.6.0 1.7 ${build.version}-SNAPSHOT - 0.9.0 + 0.8.3 -LOCAL diff --git a/src/main/java/world/bentobox/challenges/utils/HeadLib.java b/src/main/java/world/bentobox/challenges/utils/HeadLib.java index 066f75b..d08b06e 100644 --- a/src/main/java/world/bentobox/challenges/utils/HeadLib.java +++ b/src/main/java/world/bentobox/challenges/utils/HeadLib.java @@ -113,7 +113,13 @@ public enum HeadLib TRADER_LLAMA("47dbdab5-105f-42bc-9580-c61cee9231f3", "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzA4N2E1NTZkNGZmYTk1ZWNkMjg0NGYzNTBkYzQzZTI1NGU1ZDUzNWZhNTk2ZjU0MGQ3ZTc3ZmE2N2RmNDY5NiJ9fX0="), WANDERING_TRADER("943947ea-3e1a-4fdc-85e5-f538379f05e9", "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWYxMzc5YTgyMjkwZDdhYmUxZWZhYWJiYzcwNzEwZmYyZWMwMmRkMzRhZGUzODZiYzAwYzkzMGM0NjFjZjkzMiJ9fX0="), // Since 1.15 - BEE("77342662-8870-445a-869f-f0aef1406b3d", "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTlhYzE2ZjI5NmI0NjFkMDVlYTA3ODVkNDc3MDMzZTUyNzM1OGI0ZjMwYzI2NmFhMDJmMDIwMTU3ZmZjYTczNiJ9fX0="); + BEE("77342662-8870-445a-869f-f0aef1406b3d", "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTlhYzE2ZjI5NmI0NjFkMDVlYTA3ODVkNDc3MDMzZTUyNzM1OGI0ZjMwYzI2NmFhMDJmMDIwMTU3ZmZjYTczNiJ9fX0="), + // Since 1.16 + PIGLIN("7b3f9b15-325b-4d6e-a184-0455e233a1cc", "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2NlZDlkODAxYWE2ZjgzZjhlNDlmOTBkOWE4Yjg1YjdmOGZkYTU4M2Q4NWY3MmNmZmI2OTg2NzI1Nzg5ZjYzNiJ9fX0="), + ZOMBIFIED_PIGLIN("4f013cfb-84f8-4d80-8529-25127f6c70ee", "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2VhYmFlY2M1ZmFlNWE4YTQ5Yzg4NjNmZjQ4MzFhYWEyODQxOThmMWEyMzk4ODkwYzc2NWUwYThkZTE4ZGE4YyJ9fX0="), + STRIDER("d1c2fba9-6633-4625-9cda-8528fae6fe09", "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMThhOWFkZjc4MGVjN2RkNDYyNWM5YzA3NzkwNTJlNmExNWE0NTE4NjY2MjM1MTFlNGM4MmU5NjU1NzE0YjNjMSJ9fX0="), + HOGLIN("8196c240-e96a-4434-b630-6b191ceeb480", "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWJiOWJjMGYwMWRiZDc2MmEwOGQ5ZTc3YzA4MDY5ZWQ3Yzk1MzY0YWEzMGNhMTA3MjIwODU2MWI3MzBlOGQ3NSJ9fX0="), + ZOGLIN("d6f4e7ce-dc71-4c81-97dc-df0d15d39a68", "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWZhMGFkYTM0MTFmYmE4Yjg4NTgzZDg2NGIyNTI2MDZlOTNkZmRmNjQ3NjkwZDNjZjRjMDE3YjYzYmFiMTJiMCJ9fX0="); // --------------------------------------------------------------------- From d69049b91943f1518346190afb08a3cde6876cba Mon Sep 17 00:00:00 2001 From: BONNe Date: Thu, 9 Jul 2020 22:48:01 +0300 Subject: [PATCH 16/20] Update readMe file. --- README.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index f95d526..e8e3dee 100644 --- a/README.md +++ b/README.md @@ -7,14 +7,12 @@ Add-on for BentoBox to provide challenges for any BentoBox GameMode. ## Where to find Currently Challenges Addon is in **Beta stage**, so it may or may not contain bugs... a lot of bugs. Also it means, that some features are not working or implemented. -Latest official **Beta Release is 0.8.1**, and you can download it from [Release tab](https://github.com/BentoBoxWorld/Challenges/releases) -But it will work with BentoBox 1.6.x and BentoBox 1.7.x. +Latest official **Beta Release is 0.8.3**, and you can download it from [Release tab](https://github.com/BentoBoxWorld/Challenges/releases) +But it will work with BentoBox 1.14. -Latest development builds will be based on **Minecraft 1.14.4** and **BentoBox 1.8.0**. +Latest development builds will be based on **Minecraft 1.16.1** and **BentoBox 1.14.0**. **Nightly builds** are available in [Jenkins Server](https://ci.codemc.org/job/BentoBoxWorld/job/Challenges/lastStableBuild/). -Be aware that 0.8.0 stores data differently than it is in 0.7.5 and below. It will be necessary to migrate data via command `/[gamemode_admin] challenges migrate`. - If you like this addon but something is missing or is not working as you want, you can always submit an [Issue request](https://github.com/BentoBoxWorld/Challenges/issues) or get a support in Discord [BentoBox ![icon](https://avatars2.githubusercontent.com/u/41555324?s=15&v=4)](https://discord.bentobox.world) ## Translations @@ -38,7 +36,7 @@ There exist also Web Library, where users can download public challenges. It is ## Compatibility -- [x] BentoBox - 1.6.x and 1.7.x versions +- [x] BentoBox - 1.14 versions - [x] BSkyBlock - [x] AcidIsland - [x] SkyGrid @@ -46,4 +44,4 @@ There exist also Web Library, where users can download public challenges. It is ## Information -More information can be found in [Wiki Pages](https://github.com/BentoBoxWorld/Challenges/wiki). +More information can be found in [Wiki Pages](https://docs.bentobox.world/addons/Challenges/). From 6a79351685d358b8b30a8afdc715090d66796ded Mon Sep 17 00:00:00 2001 From: BONNe Date: Thu, 9 Jul 2020 23:03:52 +0300 Subject: [PATCH 17/20] Add 1.15.2 Compaitbility issue with pig_zombie egg. --- .../java/world/bentobox/challenges/utils/GuiUtils.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/world/bentobox/challenges/utils/GuiUtils.java b/src/main/java/world/bentobox/challenges/utils/GuiUtils.java index 40b069c..55edbb9 100644 --- a/src/main/java/world/bentobox/challenges/utils/GuiUtils.java +++ b/src/main/java/world/bentobox/challenges/utils/GuiUtils.java @@ -114,9 +114,6 @@ public class GuiUtils switch (entity) { - case PIG_ZOMBIE: - itemStack = new ItemStack(Material.ZOMBIE_PIGMAN_SPAWN_EGG); - break; case ENDER_DRAGON: itemStack = new ItemStack(Material.DRAGON_EGG); break; @@ -153,6 +150,12 @@ public class GuiUtils break; } + if (entity.name().equals("PIG_ZOMBIE")) + { + // If pig zombie exist, then pigman spawn egg exists too. + itemStack = new ItemStack(Material.getMaterial("ZOMBIE_PIGMAN_SPAWN_EGG")); + } + itemStack.setAmount(amount); return itemStack; From d3094053eb208251cdb223a3f39958da02da8c1b Mon Sep 17 00:00:00 2001 From: BONNe Date: Thu, 9 Jul 2020 23:25:25 +0300 Subject: [PATCH 18/20] Fixes #239 --- .../panel/admin/ListLibraryGUI.java | 55 ++++++++++++++++++- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/src/main/java/world/bentobox/challenges/panel/admin/ListLibraryGUI.java b/src/main/java/world/bentobox/challenges/panel/admin/ListLibraryGUI.java index 179cbb1..d153da3 100644 --- a/src/main/java/world/bentobox/challenges/panel/admin/ListLibraryGUI.java +++ b/src/main/java/world/bentobox/challenges/panel/admin/ListLibraryGUI.java @@ -7,6 +7,7 @@ import java.util.List; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.World; +import org.bukkit.scheduler.BukkitTask; import world.bentobox.bentobox.api.panels.PanelItem; import world.bentobox.bentobox.api.panels.builders.PanelBuilder; @@ -118,7 +119,7 @@ public class ListLibraryGUI extends CommonGUI } panelBuilder.item(4, this.createDownloadNow()); - panelBuilder.item(44, this.returnButton); + panelBuilder.item(44, this.createReturnButton()); panelBuilder.build(); } @@ -153,10 +154,16 @@ public class ListLibraryGUI extends CommonGUI } else { - this.addon.getWebManager().requestCatalogGitHubData(false); + this.addon.getWebManager().requestCatalogGitHubData(this.clearCache); + + // Fix multiclick issue. + if (this.updateTask != null) + { + this.updateTask.cancel(); + } // add some delay to rebuilding gui. - this.addon.getPlugin().getServer().getScheduler().runTaskLaterAsynchronously( + this.updateTask = this.addon.getPlugin().getServer().getScheduler().runTaskLater( this.addon.getPlugin(), this::build, 100L); @@ -169,6 +176,33 @@ public class ListLibraryGUI extends CommonGUI } + /** + * This creates return button, that allows to exist or return to parent gui, + * @return PanelItem for return button. + */ + private PanelItem createReturnButton() + { + return new PanelItemBuilder(). + name(this.user.getTranslation("challenges.gui.buttons.return")). + icon(Material.OAK_DOOR). + clickHandler((panel, user1, clickType, i) -> { + if (this.updateTask != null) + { + this.updateTask.cancel(); + } + + if (this.parentGUI == null) + { + this.user.closeInventory(); + return true; + } + + this.parentGUI.build(); + return true; + }).build(); + } + + /** * This method creates button for given library entry. * @param libraryEntry LibraryEntry which button must be created. @@ -199,10 +233,20 @@ public class ListLibraryGUI extends CommonGUI if (this.parentGUI != null) { + if (this.updateTask != null) + { + this.updateTask.cancel(); + } + this.parentGUI.build(); } else { + if (this.updateTask != null) + { + this.updateTask.cancel(); + } + this.user.closeInventory(); } } @@ -252,6 +296,11 @@ public class ListLibraryGUI extends CommonGUI */ private boolean clearCache; + /** + * Stores update task that is triggered. + */ + private BukkitTask updateTask = null; + /** * This variable will protect against spam-click. */ From 445e5a03e22360fc670117abaa40340cab6e6c95 Mon Sep 17 00:00:00 2001 From: BONNe Date: Fri, 10 Jul 2020 00:42:44 +0300 Subject: [PATCH 19/20] Fixes #241 --- src/main/resources/default.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/resources/default.json b/src/main/resources/default.json index 0163aa4..e98a54f 100644 --- a/src/main/resources/default.json +++ b/src/main/resources/default.json @@ -1196,7 +1196,8 @@ }, "rewardText": "Some handy mending books and redstone ore", "rewardItems": [ - "is:\n ==: org.bukkit.inventory.ItemStack\n v: 1976\n type: ENCHANTED_BOOK\n amount: 2\n meta:\n ==: ItemMeta\n meta-type: ENCHANTED\n stored-enchants:\n MENDING: 1\n", + "is:\n ==: org.bukkit.inventory.ItemStack\n v: 1976\n type: ENCHANTED_BOOK\n amount: 1\n meta:\n ==: ItemMeta\n meta-type: ENCHANTED\n stored-enchants:\n MENDING: 1\n", + "is:\n ==: org.bukkit.inventory.ItemStack\n v: 1976\n type: ENCHANTED_BOOK\n amount: 1\n meta:\n ==: ItemMeta\n meta-type: ENCHANTED\n stored-enchants:\n MENDING: 1\n", "is:\n ==: org.bukkit.inventory.ItemStack\n v: 1976\n type: REDSTONE_ORE\n amount: 16\n" ], "rewardExperience": 50, @@ -1282,7 +1283,8 @@ }, "rewardText": "Some mending books and lapis ore", "rewardItems": [ - "is:\n ==: org.bukkit.inventory.ItemStack\n v: 1976\n type: ENCHANTED_BOOK\n amount: 2\n meta:\n ==: ItemMeta\n meta-type: ENCHANTED\n stored-enchants:\n MENDING: 1\n", + "is:\n ==: org.bukkit.inventory.ItemStack\n v: 1976\n type: ENCHANTED_BOOK\n amount: 1\n meta:\n ==: ItemMeta\n meta-type: ENCHANTED\n stored-enchants:\n MENDING: 1\n", + "is:\n ==: org.bukkit.inventory.ItemStack\n v: 1976\n type: ENCHANTED_BOOK\n amount: 1\n meta:\n ==: ItemMeta\n meta-type: ENCHANTED\n stored-enchants:\n MENDING: 1\n", "is:\n ==: org.bukkit.inventory.ItemStack\n v: 1976\n type: LAPIS_ORE\n amount: 16\n" ], "rewardExperience": 50, From 15655b821d137e9cf71ab21db7d97e57ad4e2f2e Mon Sep 17 00:00:00 2001 From: BONNe Date: Fri, 10 Jul 2020 00:55:11 +0300 Subject: [PATCH 20/20] Fixes #222 --- .../bentobox/challenges/ChallengesManager.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main/java/world/bentobox/challenges/ChallengesManager.java b/src/main/java/world/bentobox/challenges/ChallengesManager.java index 28a7c70..6be8e14 100644 --- a/src/main/java/world/bentobox/challenges/ChallengesManager.java +++ b/src/main/java/world/bentobox/challenges/ChallengesManager.java @@ -1084,7 +1084,20 @@ public class ChallengesManager private void resetAllChallenges(@NonNull String storageDataID, @NonNull String gameMode) { this.addPlayerData(storageDataID); - this.playerCacheData.get(storageDataID).reset(gameMode); + + if (this.playerCacheData.containsKey(storageDataID)) + { + // There may be a rare situation when player data cannot be loaded. Just avoid + // error. + this.playerCacheData.get(storageDataID).reset(gameMode); + } + else + { + // If object cannot be loaded remove it completely. + this.playersDatabase.deleteID(storageDataID); + this.addon.logError("Database object was not loaded. It is removed completely. Object Id: " + storageDataID); + } + // Save this.savePlayerData(storageDataID); } @@ -1399,7 +1412,7 @@ public class ChallengesManager * @param world - World where challenges must be reset. * @param adminID - admin iD */ - public void resetAllChallenges(UUID userID, World world, UUID adminID) + public void resetAllChallenges(@NonNull UUID userID, World world, @Nullable UUID adminID) { String storageID = this.getDataUniqueID(userID, Util.getWorld(world));