diff --git a/src/main/java/world/bentobox/challenges/ChallengesManager.java b/src/main/java/world/bentobox/challenges/ChallengesManager.java index 6be8e14..4524ac1 100644 --- a/src/main/java/world/bentobox/challenges/ChallengesManager.java +++ b/src/main/java/world/bentobox/challenges/ChallengesManager.java @@ -279,6 +279,17 @@ public class ChallengesManager return false; } + if (!challenge.isValid()) + { + if (!silent) + { + user.sendMessage("challenges.errors.invalid-challenge", "[challenge]", challenge.getUniqueId()); + } + + this.addon.logWarning("Data for challenge `" + challenge.getUniqueId() + "` is not valid. It could be NULL element in item-stack!"); + return false; + } + if (this.challengeCacheData.containsKey(challenge.getUniqueId())) { if (!overwrite) @@ -352,6 +363,17 @@ public class ChallengesManager return false; } + if (!level.isValid()) + { + if (!silent) + { + user.sendMessage("challenges.errors.invalid-level", "[level]", level.getUniqueId()); + } + + this.addon.logWarning("Data for level `" + level.getUniqueId() + "` is not valid. It could be NULL element in item-stack!"); + return false; + } + if (!this.isValidLevel(level)) { if (user != null) 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 a8990cc..fb14d8a 100644 --- a/src/main/java/world/bentobox/challenges/database/object/Challenge.java +++ b/src/main/java/world/bentobox/challenges/database/object/Challenge.java @@ -1,12 +1,7 @@ package world.bentobox.challenges.database.object; -import java.util.ArrayList; -import java.util.EnumMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; import org.bukkit.Material; @@ -18,6 +13,7 @@ import org.eclipse.jdt.annotation.NonNull; import com.google.gson.annotations.Expose; import com.google.gson.annotations.JsonAdapter; +import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.database.objects.DataObject; import world.bentobox.bentobox.database.objects.Table; import world.bentobox.challenges.database.object.adapters.EntityCompatibilityAdapter; @@ -1104,6 +1100,32 @@ public class Challenge implements DataObject } + /** + * This method checks if variable values are valid for current level. + * @return {@code true} if all object values are valid, {@code false} otherwise. + */ + public boolean isValid() + { + return this.uniqueId != null && + !this.uniqueId.isEmpty() && + this.friendlyName != null && + this.description != null && + this.icon != null && + this.challengeType != null && + this.environment != null && + this.level != null && + + this.requirements.isValid() && + + this.rewardText != null && + this.rewardItems.stream().noneMatch(Objects::isNull) && + this.rewardCommands != null && + + this.repeatRewardText != null && + this.repeatItemReward.stream().noneMatch(Objects::isNull) && + this.repeatRewardCommands != null; + } + /** * Clone method that returns clone of current challenge. * @return Challenge that is cloned from current object. @@ -1114,13 +1136,8 @@ public class Challenge implements DataObject Challenge clone; try - { - clone = (Challenge) super.clone(); - } - catch (CloneNotSupportedException e) { clone = new Challenge(); - clone.setUniqueId(this.uniqueId); clone.setFriendlyName(this.friendlyName); clone.setDeployed(this.deployed); @@ -1133,7 +1150,9 @@ public class Challenge implements DataObject clone.setRemoveWhenCompleted(this.removeWhenCompleted); clone.setRequirements(this.requirements.clone()); clone.setRewardText(this.rewardText); - clone.setRewardItems(this.rewardItems.stream().map(ItemStack::clone). + clone.setRewardItems( + this.rewardItems.stream(). + map(ItemStack::clone). collect(Collectors.toCollection(() -> new ArrayList<>(this.rewardItems.size())))); clone.setRewardExperience(this.rewardExperience); clone.setRewardMoney(this.rewardMoney); @@ -1142,11 +1161,20 @@ public class Challenge implements DataObject clone.setRepeatRewardText(this.repeatRewardText); clone.setMaxTimes(this.maxTimes); clone.setRepeatExperienceReward(this.repeatExperienceReward); - clone.setRepeatItemReward(this.repeatItemReward.stream().map(ItemStack::clone). + clone.setRepeatItemReward( + this.repeatItemReward.stream(). + map(ItemStack::clone). collect(Collectors.toCollection(() -> new ArrayList<>(this.repeatItemReward.size())))); clone.setRepeatMoneyReward(this.repeatMoneyReward); clone.setRepeatRewardCommands(new ArrayList<>(this.repeatRewardCommands)); } + catch (Exception e) + { + BentoBox.getInstance().logError("Failed to clone Challenge " + this.uniqueId); + BentoBox.getInstance().logStacktrace(e); + clone = this; + this.deployed = false; + } return clone; } 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 63c108d..d5baf35 100644 --- a/src/main/java/world/bentobox/challenges/database/object/ChallengeLevel.java +++ b/src/main/java/world/bentobox/challenges/database/object/ChallengeLevel.java @@ -1,10 +1,7 @@ package world.bentobox.challenges.database.object; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; import org.bukkit.Material; @@ -12,11 +9,13 @@ import org.bukkit.inventory.ItemStack; import com.google.gson.annotations.Expose; +import world.bentobox.bentobox.BentoBox; 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; + /** * Represent a challenge level * @author tastybento @@ -520,6 +519,25 @@ public class ChallengeLevel implements DataObject, Comparable } + /** + * This method checks if variable values are valid for current level. + * @return {@code true} if all object values are valid, {@code false} otherwise. + */ + public boolean isValid() + { + return this.uniqueId != null && + !this.uniqueId.isEmpty() && + this.friendlyName != null && + this.challenges != null && + this.icon != null && + this.world != null && + this.unlockMessage != null && + this.rewardText != null && + this.rewardItems.stream().noneMatch(Objects::isNull) && + this.rewardCommands != null; + } + + /** * Clone method that returns clone of current challengeLevel. * @return ChallengeLevel that is cloned from current object. @@ -527,15 +545,10 @@ public class ChallengeLevel implements DataObject, Comparable @Override public ChallengeLevel clone() { - ChallengeLevel clone; + ChallengeLevel clone = new ChallengeLevel(); try { - clone = (ChallengeLevel) super.clone(); - } - catch (CloneNotSupportedException e) - { - clone = new ChallengeLevel(); clone.setUniqueId(this.uniqueId); clone.setFriendlyName(this.friendlyName); clone.setIcon(this.icon.clone()); @@ -545,12 +558,21 @@ public class ChallengeLevel implements DataObject, Comparable clone.setWaiverAmount(this.waiverAmount); clone.setUnlockMessage(this.unlockMessage); clone.setRewardText(this.rewardText); - clone.setRewardItems(this.rewardItems.stream().map(ItemStack::clone).collect(Collectors.toCollection(() -> new ArrayList<>(this.rewardItems.size())))); + clone.setRewardItems( + this.rewardItems.stream(). + map(ItemStack::clone). + collect(Collectors.toCollection(() -> new ArrayList<>(this.rewardItems.size())))); clone.setRewardExperience(this.rewardExperience); clone.setRewardMoney(this.rewardMoney); clone.setRewardCommands(new ArrayList<>(this.rewardCommands)); clone.setChallenges(new HashSet<>(this.challenges)); } + catch (Exception e) + { + BentoBox.getInstance().logError("Failed to clone ChallengeLevel " + this.uniqueId); + BentoBox.getInstance().logStacktrace(e); + clone = this; + } return clone; } diff --git a/src/main/java/world/bentobox/challenges/database/object/requirements/InventoryRequirements.java b/src/main/java/world/bentobox/challenges/database/object/requirements/InventoryRequirements.java index 7023a2a..64741b4 100644 --- a/src/main/java/world/bentobox/challenges/database/object/requirements/InventoryRequirements.java +++ b/src/main/java/world/bentobox/challenges/database/object/requirements/InventoryRequirements.java @@ -10,6 +10,7 @@ package world.bentobox.challenges.database.object.requirements; import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; import org.bukkit.inventory.ItemStack; @@ -85,6 +86,19 @@ public class InventoryRequirements extends Requirements // --------------------------------------------------------------------- + /** + * Method isValid returns if given requirement data is valid or not. + * + * @return {@code true} if data is valid, {@code false} otherwise. + */ + @Override + public boolean isValid() + { + return super.isValid() && + this.requiredItems != null && this.requiredItems.stream().noneMatch(Objects::isNull); + } + + /** * Method Requirements#clone allows to clone Requirements object, to avoid changing content when it is necessary * to use it. 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 196c8a6..1de6737 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 @@ -7,10 +7,7 @@ package world.bentobox.challenges.database.object.requirements; -import java.util.EnumMap; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; +import java.util.*; import org.bukkit.Material; import org.bukkit.entity.EntityType; @@ -153,6 +150,20 @@ public class IslandRequirements extends Requirements // --------------------------------------------------------------------- + /** + * Method isValid returns if given requirement data is valid or not. + * + * @return {@code true} if data is valid, {@code false} otherwise. + */ + @Override + public boolean isValid() + { + return super.isValid() && + this.requiredBlocks != null && this.requiredBlocks.keySet().stream().noneMatch(Objects::isNull) && + this.requiredEntities != null && this.requiredEntities.keySet().stream().noneMatch(Objects::isNull); + } + + /** * Method Requirements#clone allows to clone Requirements object, to avoid changing content when it is necessary * to use it. diff --git a/src/main/java/world/bentobox/challenges/database/object/requirements/Requirements.java b/src/main/java/world/bentobox/challenges/database/object/requirements/Requirements.java index 09a54f5..1b292b7 100644 --- a/src/main/java/world/bentobox/challenges/database/object/requirements/Requirements.java +++ b/src/main/java/world/bentobox/challenges/database/object/requirements/Requirements.java @@ -59,6 +59,16 @@ public abstract class Requirements // --------------------------------------------------------------------- + /** + * Method isValid returns if given requirement data is valid or not. + * @return {@code true} if data is valid, {@code false} otherwise. + */ + public boolean isValid() + { + return this.requiredPermissions != null; + } + + /** * Method Requirements#clone allows to clone Requirements object, to avoid changing content when it is necessary * to use it. diff --git a/src/main/java/world/bentobox/challenges/panel/CommonGUI.java b/src/main/java/world/bentobox/challenges/panel/CommonGUI.java index 4b0db2e..e3d69af 100644 --- a/src/main/java/world/bentobox/challenges/panel/CommonGUI.java +++ b/src/main/java/world/bentobox/challenges/panel/CommonGUI.java @@ -1006,11 +1006,13 @@ public abstract class CommonGUI } else if (meta instanceof TropicalFishBucketMeta) { - result.add(this.user.getTranslation("challenges.gui.item-description.fish-meta", + if (((TropicalFishBucketMeta) meta).hasVariant()) + { + result.add(this.user.getTranslation("challenges.gui.item-description.fish-meta", "[pattern]", Util.prettifyText(((TropicalFishBucketMeta) meta).getPattern().name()), "[pattern-color]", Util.prettifyText(((TropicalFishBucketMeta) meta).getPatternColor().name()), "[body-color]", Util.prettifyText(((TropicalFishBucketMeta) meta).getBodyColor().name()))); - // parse ne + } } if (meta.hasEnchants()) diff --git a/src/main/resources/locales/en-US.yml b/src/main/resources/locales/en-US.yml index adb7cbb..d7a812a 100755 --- a/src/main/resources/locales/en-US.yml +++ b/src/main/resources/locales/en-US.yml @@ -595,6 +595,8 @@ challenges: missing-level: '&c Challenge Level [level] is not defined in the database. It may cause errors!' missing-arguments: '&c Command is missing arguments.' no-multiple-permission: "&c You do not have permission to complete this challenge multiple times at once." + invalid-level: "&c Level [level] contains invalid data. It will not be loaded from database!" + invalid-challenge: "&c Challenge [challenge] contains invalid data. It will not be loaded from database!" protection: flags: CHALLENGES_ISLAND_PROTECTION: