Rework Challenge Object Data storing.

Requires MIGRATION if upgrade from older version.
This commit is contained in:
BONNe 2019-09-08 20:03:46 +03:00
parent 09036a28f0
commit 4e6d37cd90
16 changed files with 4354 additions and 3278 deletions

View File

@ -11,6 +11,7 @@ import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.configuration.Config;
import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.database.DatabaseSetup.DatabaseType;
import world.bentobox.bentobox.hooks.VaultHook;
import world.bentobox.bentobox.managers.RanksManager;
import world.bentobox.challenges.commands.ChallengesCommand;
@ -18,7 +19,11 @@ import world.bentobox.challenges.commands.ChallengesUserCommand;
import world.bentobox.challenges.commands.admin.Challenges;
import world.bentobox.challenges.commands.admin.ChallengesAdminCommand;
import world.bentobox.challenges.config.Settings;
import world.bentobox.challenges.handlers.*;
import world.bentobox.challenges.handlers.ChallengeDataRequestHandler;
import world.bentobox.challenges.handlers.ChallengeListRequestHandler;
import world.bentobox.challenges.handlers.CompletedChallengesRequestHandler;
import world.bentobox.challenges.handlers.LevelDataRequestHandler;
import world.bentobox.challenges.handlers.LevelListRequestHandler;
import world.bentobox.challenges.listeners.ResetListener;
import world.bentobox.challenges.listeners.SaveListener;
import world.bentobox.challenges.web.WebManager;
@ -127,7 +132,7 @@ public class ChallengesAddon extends Addon {
public void onEnable() {
// Check if it is enabled - it might be loaded, but not enabled.
if (this.getPlugin() == null || !this.getPlugin().isEnabled()) {
Bukkit.getLogger().severe("BentoBox is not available or disabled!");
this.logError("BentoBox is not available or disabled!");
this.setState(State.DISABLED);
return;
}
@ -135,7 +140,15 @@ public class ChallengesAddon extends Addon {
// Check if addon is not disabled before.
if (this.getState().equals(State.DISABLED))
{
Bukkit.getLogger().severe("Challenges Addon is not available or disabled!");
this.logError("Challenges Addon is not available or disabled!");
return;
}
if (this.isInCompatibleDatabase())
{
this.logError("BentoBox database is not compatible with Challenges Addon.");
this.logError("Please use JSON based database type.");
this.setState(State.DISABLED);
return;
}
@ -294,6 +307,16 @@ public class ChallengesAddon extends Addon {
}
/**
* This method checks if database is compatible with Challenges addon.
* @return {@code true} if database type is YAML, {@code false} - otherwise.
*/
private boolean isInCompatibleDatabase()
{
return this.getPlugin().getSettings().getDatabaseType().equals(DatabaseType.YAML);
}
// ---------------------------------------------------------------------
// Section: Getters
// ---------------------------------------------------------------------

View File

@ -3,10 +3,19 @@ package world.bentobox.challenges;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;
import java.io.*;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.bukkit.World;
@ -28,7 +37,7 @@ import world.bentobox.challenges.utils.Utils;
public class ChallengesImportManager
{
/**
* Import challenges from challenges.yml
* Import challenges from default.json
* @param challengesAddon
*/
public ChallengesImportManager(ChallengesAddon challengesAddon)
@ -328,7 +337,7 @@ public class ChallengesImportManager
/**
* This Class allows to load default challenges and their levels as objects much easier.
*/
private final class DefaultJSONHandler
private static final class DefaultJSONHandler
{
/**
* This constructor inits JSON builder that will be used to parse challenges.
@ -375,19 +384,24 @@ public class ChallengesImportManager
{
File defaultFile = new File(this.addon.getDataFolder(), "default.json");
StringBuilder builder = new StringBuilder();
try (InputStreamReader reader = new InputStreamReader(new FileInputStream(defaultFile), StandardCharsets.UTF_8))
{
DefaultDataHolder object = this.gson.fromJson(reader, DefaultDataHolder.class);
try
{
Files.readAllLines(defaultFile.toPath()).forEach(builder::append);
reader.close(); // NOSONAR Required to keep OS file handlers low and not rely on GC
return object;
}
catch (IOException e)
catch (FileNotFoundException e)
{
e.printStackTrace();
this.addon.logError("Could not load file '" + defaultFile.getName() + "': File not found.");
}
catch (Exception e)
{
this.addon.logError("Could not load objects " + defaultFile.getName() + " " + e.getMessage());
}
return this.gson.fromJson(builder.toString(), DefaultDataHolder.class);
return null;
}
@ -422,7 +436,7 @@ public class ChallengesImportManager
* This is simple object that will allow to store all current challenges and levels
* in single file.
*/
private final class DefaultDataHolder implements DataObject
private static final class DefaultDataHolder implements DataObject
{
/**
* Default constructor. Creates object with empty lists.
@ -439,7 +453,7 @@ public class ChallengesImportManager
* This method returns stored challenge list.
* @return list that contains default challenges.
*/
public List<Challenge> getChallengeList()
List<Challenge> getChallengeList()
{
return challengeList;
}
@ -449,7 +463,7 @@ public class ChallengesImportManager
* This method sets given list as default challenge list.
* @param challengeList new default challenge list.
*/
public void setChallengeList(List<Challenge> challengeList)
void setChallengeList(List<Challenge> challengeList)
{
this.challengeList = challengeList;
}
@ -459,7 +473,7 @@ public class ChallengesImportManager
* This method returns list of default challenge levels.
* @return List that contains default challenge levels.
*/
public List<ChallengeLevel> getLevelList()
List<ChallengeLevel> getLevelList()
{
return challengeLevelList;
}
@ -469,7 +483,7 @@ public class ChallengesImportManager
* This method sets given list as default challenge level list.
* @param levelList new default challenge level list.
*/
public void setLevelList(List<ChallengeLevel> levelList)
void setLevelList(List<ChallengeLevel> levelList)
{
this.challengeLevelList = levelList;
}

View File

@ -31,6 +31,10 @@ import world.bentobox.challenges.config.Settings;
import world.bentobox.challenges.database.object.Challenge;
import world.bentobox.challenges.database.object.ChallengeLevel;
import world.bentobox.challenges.database.object.ChallengesPlayerData;
import world.bentobox.challenges.database.object.requirements.InventoryRequirements;
import world.bentobox.challenges.database.object.requirements.IslandRequirements;
import world.bentobox.challenges.database.object.requirements.OtherRequirements;
import world.bentobox.challenges.database.object.requirements.Requirements;
import world.bentobox.challenges.events.ChallengeCompletedEvent;
import world.bentobox.challenges.events.ChallengeResetAllEvent;
import world.bentobox.challenges.events.ChallengeResetEvent;
@ -731,6 +735,49 @@ public class ChallengesManager
this.challengeDatabase.saveObject(challenge);
this.challengeCacheData.put(challenge.getUniqueId(), challenge);
}
// Migrate Requirements.
if (challenge.getRequirements() == null)
{
switch (challenge.getChallengeType())
{
case INVENTORY:
InventoryRequirements inventoryRequirements = new InventoryRequirements();
inventoryRequirements.setRequiredItems(challenge.getRequiredItems());
inventoryRequirements.setTakeItems(challenge.isTakeItems());
inventoryRequirements.setRequiredPermissions(challenge.getRequiredPermissions());
challenge.setRequirements(inventoryRequirements);
break;
case ISLAND:
IslandRequirements islandRequirements = new IslandRequirements();
islandRequirements.setRemoveBlocks(challenge.isRemoveBlocks());
islandRequirements.setRemoveEntities(challenge.isRemoveEntities());
islandRequirements.setRequiredBlocks(challenge.getRequiredBlocks());
islandRequirements.setRequiredEntities(challenge.getRequiredEntities());
islandRequirements.setSearchRadius(challenge.getSearchRadius());
islandRequirements.setRequiredPermissions(challenge.getRequiredPermissions());
challenge.setRequirements(islandRequirements);
break;
case OTHER:
OtherRequirements otherRequirements = new OtherRequirements();
otherRequirements.setRequiredExperience(challenge.getRequiredExperience());
otherRequirements.setRequiredIslandLevel(challenge.getRequiredIslandLevel());
otherRequirements.setRequiredMoney(challenge.getRequiredMoney());
otherRequirements.setTakeExperience(challenge.isTakeExperience());
otherRequirements.setTakeMoney(challenge.isTakeMoney());
otherRequirements.setRequiredPermissions(challenge.getRequiredPermissions());
challenge.setRequirements(otherRequirements);
break;
}
// This save should not involve any upgrades in other parts.
this.challengeDatabase.saveObject(challenge);
this.challengeCacheData.put(challenge.getUniqueId(), challenge);
}
}
return updated;
@ -1642,14 +1689,17 @@ public class ChallengesManager
/**
* This method creates and returns new challenge with given uniqueID.
* @param uniqueID - new ID for challenge.
* @param requirements - requirements object, as it is not changeable anymore.
* @return Challenge that is currently created.
*/
public Challenge createChallenge(String uniqueID)
public Challenge createChallenge(String uniqueID, Challenge.ChallengeType type, Requirements requirements)
{
if (!this.containsChallenge(uniqueID))
{
Challenge challenge = new Challenge();
challenge.setUniqueId(uniqueID);
challenge.setRequirements(requirements);
challenge.setChallengeType(type);
this.saveChallenge(challenge);
this.loadChallenge(challenge);

View File

@ -1,7 +1,12 @@
package world.bentobox.challenges.database.object;
import java.util.*;
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.stream.Collectors;
import org.bukkit.Material;
@ -10,9 +15,11 @@ import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.JsonAdapter;
import world.bentobox.bentobox.api.configuration.ConfigComment;
import world.bentobox.bentobox.database.objects.DataObject;
import world.bentobox.challenges.database.object.adapters.RequirementsAdapter;
import world.bentobox.challenges.database.object.requirements.Requirements;
/**
@ -57,57 +64,65 @@ public class Challenge implements DataObject
// Section: Variables
// ---------------------------------------------------------------------
@ConfigComment("")
@ConfigComment("Unique name of the challenge")
/**
* Unique name for challenge object.
*/
@Expose
private String uniqueId = "";
@ConfigComment("")
@ConfigComment("The name of the challenge. May include color codes. Single line.")
/**
* The name of the challenge. May include color codes. Single line.
*/
@Expose
private String friendlyName = "";
@ConfigComment("")
@ConfigComment("Whether this challenge is deployed or not.")
/**
* Whether this challenge is deployed or not.
*/
@Expose
private boolean deployed;
@ConfigComment("")
@ConfigComment("Description of the challenge. Will become the lore on the icon. Can ")
@ConfigComment("include & color codes. String List.")
/**
* Description of the challenge. Will become the lore on the icon. Can include & color codes. String List.
*/
@Expose
private List<String> description = new ArrayList<>();
@ConfigComment("")
@ConfigComment("The icon in the GUI for this challenge. ItemStack.")
/**
* The icon in the GUI for this challenge. ItemStack.
*/
@Expose
private ItemStack icon = new ItemStack(Material.PAPER);
@ConfigComment("")
@ConfigComment("Order of this challenge. It allows define order for challenges in")
@ConfigComment("single level. If order for challenges are equal, it will order by")
@ConfigComment("challenge unique id.")
/**
* Order of this challenge. It allows define order for challenges in
* single level. If order for challenges are equal, it will order by
* challenge unique id.
*/
@Expose
private int order = -1;
@ConfigComment("")
@ConfigComment("Challenge type can be INVENTORY, OTHER or ISLAND.")
/**
* Challenge type can be INVENTORY, OTHER or ISLAND.
*/
@Expose
private ChallengeType challengeType = ChallengeType.INVENTORY;
@ConfigComment("")
@ConfigComment("List of environments where this challenge will occur: NETHER, NORMAL,")
@ConfigComment("THE_END. Leave blank for all.")
/**
* List of environments where this challenge will occur: NETHER, NORMAL, THE_END. Leave blank for all.
*/
@Expose
private Set<World.Environment> environment = new HashSet<>();
@ConfigComment("")
@ConfigComment("If true, the challenge will disappear from the GUI when completed")
/**
* If true, the challenge will disappear from the GUI when completed
*/
@Expose
private boolean removeWhenCompleted;
@ConfigComment("")
@ConfigComment("Unique challenge ID. Empty means that challenge is in free challenge list.")
/**
* Unique level ID. Empty means that challenge is in free challenge list.
*/
@Expose
private String level = "";
@ -115,74 +130,66 @@ public class Challenge implements DataObject
// Section: Requirement related
// ---------------------------------------------------------------------
@ConfigComment("")
@ConfigComment("")
@ConfigComment("The required permissions to see this challenge. String list.")
/**
* Requirements for current challenge.
*/
@Expose
@JsonAdapter(RequirementsAdapter.class)
private Requirements requirements;
// ---------------------------------------------------------------------
// Section: Deprecated Requirements
// ---------------------------------------------------------------------
@Deprecated
@Expose
private Set<String> requiredPermissions = new HashSet<>();
@ConfigComment("")
@ConfigComment("This is a map of the blocks required in a ISLAND challenge. Material,")
@ConfigComment("Integer")
@Deprecated
@Expose
private Map<Material, Integer> requiredBlocks = new EnumMap<>(Material.class);
@ConfigComment("")
@ConfigComment("Remove the required blocks from the island")
@Deprecated
@Expose
private boolean removeBlocks;
@ConfigComment("")
@ConfigComment("Any entities that must be in the area for ISLAND type challenges. ")
@ConfigComment("Map EntityType, Number")
@Deprecated
@Expose
private Map<EntityType, Integer> requiredEntities = new EnumMap<>(EntityType.class);
@ConfigComment("")
@ConfigComment("Remove the entities from the island")
@Deprecated
@Expose
private boolean removeEntities;
@ConfigComment("")
@ConfigComment("The items that must be in the inventory to complete the challenge. ")
@ConfigComment("ItemStack List.")
@Deprecated
@Expose
private List<ItemStack> requiredItems = new ArrayList<>();
@ConfigComment("")
@ConfigComment("Take the required items from the player")
@Deprecated
@Expose
private boolean takeItems = true;
@ConfigComment("")
@ConfigComment("Required experience for challenge completion.")
@Deprecated
@Expose
private int requiredExperience = 0;
@ConfigComment("")
@ConfigComment("Take the experience from the player")
@Deprecated
@Expose
private boolean takeExperience;
@ConfigComment("")
@ConfigComment("Required money for challenge completion. Economy plugins or addons")
@ConfigComment("is required for this option.")
@Deprecated
@Expose
private int requiredMoney = 0;
@ConfigComment("")
@ConfigComment("Take the money from the player")
@Deprecated
@Expose
private boolean takeMoney;
@ConfigComment("")
@ConfigComment("Required island level for challenge completion. Plugin or Addon that")
@ConfigComment("calculates island level is required for this option.")
@Deprecated
@Expose
private long requiredIslandLevel;
@ConfigComment("")
@ConfigComment("The number of blocks around the player to search for items on an island")
@Deprecated
@Expose
private int searchRadius = 10;
@ -191,32 +198,33 @@ public class Challenge implements DataObject
// Section: Rewards
// ---------------------------------------------------------------------
@ConfigComment("")
@ConfigComment("")
@ConfigComment("If this is blank, the reward text will be auto-generated, otherwise")
@ConfigComment("this will be used.")
/**
* If this is blank, the reward text will be auto-generated, otherwise this will be used.
*/
@Expose
private String rewardText = "";
@ConfigComment("")
@ConfigComment("List of items the player will receive first time. ItemStack List.")
/**
* List of items the player will receive first time. ItemStack List.
*/
@Expose
private List<ItemStack> rewardItems = new ArrayList<>();
@ConfigComment("")
@ConfigComment("Experience point reward")
/**
* Experience point reward
*/
@Expose
private int rewardExperience = 0;
@ConfigComment("")
@ConfigComment("Money reward. Economy plugin or addon required for this option.")
/**
* Money reward. Economy plugin or addon required for this option.
*/
@Expose
private int rewardMoney = 0;
@ConfigComment("")
@ConfigComment("Commands to run when the player completes the challenge for the first")
@ConfigComment("time. String List")
/**
* Commands to run when the player completes the challenge for the first time. String List
*/
@Expose
private List<String> rewardCommands = new ArrayList<>();
@ -225,41 +233,45 @@ public class Challenge implements DataObject
// Section: Repeat Rewards
// ---------------------------------------------------------------------
@ConfigComment("")
@ConfigComment("")
@ConfigComment("True if the challenge is repeatable")
/**
* True if the challenge is repeatable
*/
@Expose
private boolean repeatable;
@ConfigComment("")
@ConfigComment("Description of the repeat rewards. If blank, it will be autogenerated.")
/**
* Description of the repeat rewards. If blank, it will be autogenerated
*/
@Expose
private String repeatRewardText = "";
@ConfigComment("")
@ConfigComment("Maximum number of times the challenge can be repeated. 0 or less")
@ConfigComment("will mean infinite times.")
/**
* Maximum number of times the challenge can be repeated. 0 or less will mean infinite times.
*/
@Expose
private int maxTimes = 1;
@ConfigComment("")
@ConfigComment("Repeat experience reward")
/**
* Repeat experience reward
*/
@Expose
private int repeatExperienceReward = 0;
@ConfigComment("")
@ConfigComment("Reward items for repeating the challenge. List of ItemStacks.")
/**
* Reward items for repeating the challenge. List of ItemStacks.
*/
@Expose
private List<ItemStack> repeatItemReward = new ArrayList<>();
@ConfigComment("")
@ConfigComment("Repeat money reward. Economy plugin or addon required for this option.")
/**
* Repeat money reward. Economy plugin or addon required for this option.
*/
@Expose
private int repeatMoneyReward;
@ConfigComment("")
@ConfigComment("Commands to run when challenge is repeated. String List.")
/**
* Commands to run when challenge is repeated. String List.
*/
@Expose
private List<String> repeatRewardCommands = new ArrayList<>();
@ -360,9 +372,21 @@ public class Challenge implements DataObject
}
/**
* Method Challenge#getRequirements returns the requirements of this object.
* @return the requirements (type Requirements) of this object.
*/
@SuppressWarnings("unchecked")
public <T extends Requirements> T getRequirements()
{
return (T) this.requirements;
}
/**
* @return the requiredPermissions
*/
@Deprecated
public Set<String> getRequiredPermissions()
{
return requiredPermissions;
@ -372,6 +396,7 @@ public class Challenge implements DataObject
/**
* @return the requiredBlocks
*/
@Deprecated
public Map<Material, Integer> getRequiredBlocks()
{
return requiredBlocks;
@ -381,6 +406,7 @@ public class Challenge implements DataObject
/**
* @return the removeBlocks
*/
@Deprecated
public boolean isRemoveBlocks()
{
return removeBlocks;
@ -390,6 +416,7 @@ public class Challenge implements DataObject
/**
* @return the requiredEntities
*/
@Deprecated
public Map<EntityType, Integer> getRequiredEntities()
{
return requiredEntities;
@ -399,6 +426,7 @@ public class Challenge implements DataObject
/**
* @return the removeEntities
*/
@Deprecated
public boolean isRemoveEntities()
{
return removeEntities;
@ -408,6 +436,7 @@ public class Challenge implements DataObject
/**
* @return the requiredItems
*/
@Deprecated
public List<ItemStack> getRequiredItems()
{
return requiredItems;
@ -417,6 +446,7 @@ public class Challenge implements DataObject
/**
* @return the takeItems
*/
@Deprecated
public boolean isTakeItems()
{
return takeItems;
@ -426,6 +456,7 @@ public class Challenge implements DataObject
/**
* @return the requiredExperience
*/
@Deprecated
public int getRequiredExperience()
{
return requiredExperience;
@ -435,6 +466,7 @@ public class Challenge implements DataObject
/**
* @return the takeExperience
*/
@Deprecated
public boolean isTakeExperience()
{
return takeExperience;
@ -444,6 +476,7 @@ public class Challenge implements DataObject
/**
* @return the requiredMoney
*/
@Deprecated
public int getRequiredMoney()
{
return requiredMoney;
@ -453,6 +486,7 @@ public class Challenge implements DataObject
/**
* @return the takeMoney
*/
@Deprecated
public boolean isTakeMoney()
{
return takeMoney;
@ -462,6 +496,7 @@ public class Challenge implements DataObject
/**
* @return the requiredIslandLevel
*/
@Deprecated
public long getRequiredIslandLevel()
{
return requiredIslandLevel;
@ -471,6 +506,7 @@ public class Challenge implements DataObject
/**
* @return the searchRadius
*/
@Deprecated
public int getSearchRadius()
{
return searchRadius;
@ -703,6 +739,7 @@ public class Challenge implements DataObject
* @param requiredPermissions the requiredPermissions new value.
*
*/
@Deprecated
public void setRequiredPermissions(Set<String> requiredPermissions)
{
this.requiredPermissions = requiredPermissions;
@ -714,6 +751,7 @@ public class Challenge implements DataObject
* @param requiredBlocks the requiredBlocks new value.
*
*/
@Deprecated
public void setRequiredBlocks(Map<Material, Integer> requiredBlocks)
{
this.requiredBlocks = requiredBlocks;
@ -725,6 +763,7 @@ public class Challenge implements DataObject
* @param removeBlocks the removeBlocks new value.
*
*/
@Deprecated
public void setRemoveBlocks(boolean removeBlocks)
{
this.removeBlocks = removeBlocks;
@ -736,6 +775,7 @@ public class Challenge implements DataObject
* @param requiredEntities the requiredEntities new value.
*
*/
@Deprecated
public void setRequiredEntities(Map<EntityType, Integer> requiredEntities)
{
this.requiredEntities = requiredEntities;
@ -747,6 +787,7 @@ public class Challenge implements DataObject
* @param removeEntities the removeEntities new value.
*
*/
@Deprecated
public void setRemoveEntities(boolean removeEntities)
{
this.removeEntities = removeEntities;
@ -758,6 +799,7 @@ public class Challenge implements DataObject
* @param requiredItems the requiredItems new value.
*
*/
@Deprecated
public void setRequiredItems(List<ItemStack> requiredItems)
{
this.requiredItems = requiredItems;
@ -769,6 +811,7 @@ public class Challenge implements DataObject
* @param takeItems the takeItems new value.
*
*/
@Deprecated
public void setTakeItems(boolean takeItems)
{
this.takeItems = takeItems;
@ -780,6 +823,7 @@ public class Challenge implements DataObject
* @param requiredExperience the requiredExperience new value.
*
*/
@Deprecated
public void setRequiredExperience(int requiredExperience)
{
this.requiredExperience = requiredExperience;
@ -791,6 +835,7 @@ public class Challenge implements DataObject
* @param takeExperience the takeExperience new value.
*
*/
@Deprecated
public void setTakeExperience(boolean takeExperience)
{
this.takeExperience = takeExperience;
@ -802,6 +847,7 @@ public class Challenge implements DataObject
* @param requiredMoney the requiredMoney new value.
*
*/
@Deprecated
public void setRequiredMoney(int requiredMoney)
{
this.requiredMoney = requiredMoney;
@ -813,6 +859,7 @@ public class Challenge implements DataObject
* @param takeMoney the takeMoney new value.
*
*/
@Deprecated
public void setTakeMoney(boolean takeMoney)
{
this.takeMoney = takeMoney;
@ -824,6 +871,7 @@ public class Challenge implements DataObject
* @param requiredIslandLevel the requiredIslandLevel new value.
*
*/
@Deprecated
public void setRequiredIslandLevel(long requiredIslandLevel)
{
this.requiredIslandLevel = requiredIslandLevel;
@ -835,6 +883,7 @@ public class Challenge implements DataObject
* @param searchRadius the searchRadius new value.
*
*/
@Deprecated
public void setSearchRadius(int searchRadius)
{
this.searchRadius = searchRadius;
@ -973,6 +1022,17 @@ public class Challenge implements DataObject
}
/**
* Method Challenge#setRequirements sets new value for the requirements of this object.
* @param requirements new value for this object.
*
*/
public void setRequirements(Requirements requirements)
{
this.requirements = requirements;
}
// ---------------------------------------------------------------------
// Section: Other methods
// ---------------------------------------------------------------------
@ -1066,21 +1126,10 @@ public class Challenge implements DataObject
clone.setEnvironment(new HashSet<>(this.environment));
clone.setLevel(this.level);
clone.setRemoveWhenCompleted(this.removeWhenCompleted);
clone.setRequiredPermissions(new HashSet<>(this.requiredPermissions));
clone.setRequiredBlocks(new HashMap<>(this.requiredBlocks));
clone.setRemoveBlocks(this.removeBlocks);
clone.setRequiredEntities(new HashMap<>(this.requiredEntities));
clone.setRemoveEntities(this.removeEntities);
clone.setRequiredItems(this.requiredItems.stream().map(ItemStack::clone).collect(Collectors.toCollection(() -> new ArrayList<>(this.requiredItems.size()))));
clone.setTakeItems(this.takeItems);
clone.setRequiredExperience(this.requiredExperience);
clone.setTakeExperience(this.takeExperience);
clone.setRequiredMoney(this.requiredMoney);
clone.setTakeMoney(this.takeMoney);
clone.setRequiredIslandLevel(this.requiredIslandLevel);
clone.setSearchRadius(this.searchRadius);
clone.setRequirements(this.requirements.clone());
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));
@ -1088,7 +1137,8 @@ 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).collect(Collectors.toCollection(() -> new ArrayList<>(this.repeatItemReward.size()))));
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));
}

View File

@ -0,0 +1,71 @@
//
// Created by BONNe
// Copyright - 2019
//
package world.bentobox.challenges.database.object.adapters;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
import world.bentobox.challenges.database.object.requirements.Requirements;
/**
* This is a generic JSON serializer and deserializer for abstract classes.
* It store target class in class object, and instance variables in variables object.
*/
public class RequirementsAdapter implements JsonSerializer<Requirements>, JsonDeserializer<Requirements>
{
/**
* This class allows to serialize all Requirements classes.
*/
@Override
public JsonElement serialize(Requirements src, Type typeOfSrc, JsonSerializationContext context)
{
JsonObject result = new JsonObject();
result.add("class", new JsonPrimitive(src.getClass().getSimpleName()));
result.add("parameters", context.serialize(src, src.getClass()));
return result;
}
/**
* This class allows to deserialize json element to correct Requirements class.
*/
@Override
public Requirements deserialize(JsonElement json,
Type typeOfT,
JsonDeserializationContext context)
throws JsonParseException
{
JsonObject jsonObject = json.getAsJsonObject();
String type = jsonObject.get("class").getAsString();
JsonElement element = jsonObject.get("parameters");
try
{
return context.deserialize(element, Class.forName(PACKAGE + type));
}
catch (ClassNotFoundException e)
{
throw new JsonParseException("Unknown element type: " + type, e);
}
}
/**
* Package location of all requirement classes.
*/
private static final String PACKAGE = "world.bentobox.challenges.database.object.requirements.";
}

View File

@ -0,0 +1,121 @@
//
// Created by BONNe
// Copyright - 2019
//
package world.bentobox.challenges.database.object.requirements;
import com.google.gson.annotations.Expose;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;
/**
* This class contains all necessary requirements to complete inventory type challenge.
*/
public class InventoryRequirements extends Requirements
{
/**
* Constructor Requirements creates a new Requirements instance.
*/
public InventoryRequirements()
{
// Empty constructor
}
// ---------------------------------------------------------------------
// Section: Getters and Setters
// ---------------------------------------------------------------------
/**
* Method InventoryRequirements#getRequiredItems returns the requiredItems of this object.
*
* @return the requiredItems (type List<ItemStack>) of this object.
*/
public List<ItemStack> getRequiredItems()
{
return requiredItems;
}
/**
* Method InventoryRequirements#setRequiredItems sets new value for the requiredItems of this object.
* @param requiredItems new value for this object.
*
*/
public void setRequiredItems(List<ItemStack> requiredItems)
{
this.requiredItems = requiredItems;
}
/**
* Method InventoryRequirements#isTakeItems returns the takeItems of this object.
*
* @return the takeItems (type boolean) of this object.
*/
public boolean isTakeItems()
{
return takeItems;
}
/**
* Method InventoryRequirements#setTakeItems sets new value for the takeItems of this object.
* @param takeItems new value for this object.
*
*/
public void setTakeItems(boolean takeItems)
{
this.takeItems = takeItems;
}
// ---------------------------------------------------------------------
// Section: Other methods
// ---------------------------------------------------------------------
/**
* Method Requirements#clone allows to clone Requirements object, to avoid changing content when it is necessary
* to use it.
* @return InventoryRequirements clone
*/
@Override
public Requirements clone()
{
InventoryRequirements clone = new InventoryRequirements();
clone.setRequiredPermissions(new HashSet<>(this.getRequiredPermissions()));
clone.setRequiredItems(this.requiredItems.stream().
map(ItemStack::clone).
collect(Collectors.toCollection(() -> new ArrayList<>(this.requiredItems.size()))));
clone.setTakeItems(this.takeItems);
return clone;
}
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
/**
* List of required ItemStacks in players inventory to complete this challenge.
*/
@Expose
private List<ItemStack> requiredItems = new ArrayList<>();
/**
* Boolean that indicate if challenge completion should remove items from inventory.
*/
@Expose
private boolean takeItems = true;
}

View File

@ -0,0 +1,207 @@
//
// Created by BONNe
// Copyright - 2019
//
package world.bentobox.challenges.database.object.requirements;
import com.google.gson.annotations.Expose;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
/**
* This class contains all necessary requirements to complete island type challenge.
*/
public class IslandRequirements extends Requirements
{
/**
* Constructor Requirements creates a new Requirements instance.
*/
public IslandRequirements()
{
// Empty constructor for data loader
}
// ---------------------------------------------------------------------
// Section: Getters and Setters
// ---------------------------------------------------------------------
/**
* Method IslandRequirements#getRequiredBlocks returns the requiredBlocks of this object.
*
* @return the requiredBlocks (type Map<Material, Integer>) of this object.
*/
public Map<Material, Integer> getRequiredBlocks()
{
return requiredBlocks;
}
/**
* Method IslandRequirements#setRequiredBlocks sets new value for the requiredBlocks of this object.
* @param requiredBlocks new value for this object.
*
*/
public void setRequiredBlocks(Map<Material, Integer> requiredBlocks)
{
this.requiredBlocks = requiredBlocks;
}
/**
* Method IslandRequirements#isRemoveBlocks returns the removeBlocks of this object.
*
* @return the removeBlocks (type boolean) of this object.
*/
public boolean isRemoveBlocks()
{
return removeBlocks;
}
/**
* Method IslandRequirements#setRemoveBlocks sets new value for the removeBlocks of this object.
* @param removeBlocks new value for this object.
*
*/
public void setRemoveBlocks(boolean removeBlocks)
{
this.removeBlocks = removeBlocks;
}
/**
* Method IslandRequirements#getRequiredEntities returns the requiredEntities of this object.
*
* @return the requiredEntities (type Map<EntityType, Integer>) of this object.
*/
public Map<EntityType, Integer> getRequiredEntities()
{
return requiredEntities;
}
/**
* Method IslandRequirements#setRequiredEntities sets new value for the requiredEntities of this object.
* @param requiredEntities new value for this object.
*
*/
public void setRequiredEntities(Map<EntityType, Integer> requiredEntities)
{
this.requiredEntities = requiredEntities;
}
/**
* Method IslandRequirements#isRemoveEntities returns the removeEntities of this object.
*
* @return the removeEntities (type boolean) of this object.
*/
public boolean isRemoveEntities()
{
return removeEntities;
}
/**
* Method IslandRequirements#setRemoveEntities sets new value for the removeEntities of this object.
* @param removeEntities new value for this object.
*
*/
public void setRemoveEntities(boolean removeEntities)
{
this.removeEntities = removeEntities;
}
/**
* Method IslandRequirements#getSearchRadius returns the searchRadius of this object.
*
* @return the searchRadius (type int) of this object.
*/
public int getSearchRadius()
{
return searchRadius;
}
/**
* Method IslandRequirements#setSearchRadius sets new value for the searchRadius of this object.
* @param searchRadius new value for this object.
*
*/
public void setSearchRadius(int searchRadius)
{
this.searchRadius = searchRadius;
}
// ---------------------------------------------------------------------
// Section: Other methods
// ---------------------------------------------------------------------
/**
* Method Requirements#clone allows to clone Requirements object, to avoid changing content when it is necessary
* to use it.
* @return IslandRequirements clone
*/
@Override
public Requirements clone()
{
IslandRequirements clone = new IslandRequirements();
clone.setRequiredPermissions(new HashSet<>(this.getRequiredPermissions()));
clone.setRequiredBlocks(new HashMap<>(this.requiredBlocks));
clone.setRemoveBlocks(this.removeBlocks);
clone.setRequiredEntities(new HashMap<>(this.requiredEntities));
clone.setRemoveEntities(this.removeEntities);
clone.setSearchRadius(this.searchRadius);
return clone;
}
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
/**
* Map that contains which materials and how many is necessary around player to complete challenge.
*/
@Expose
private Map<Material, Integer> requiredBlocks = new EnumMap<>(Material.class);
/**
* Boolean that indicate if blocks should be removed from world after completion.
*/
@Expose
private boolean removeBlocks;
/**
* Map that contains which entities and how many is necessary around player to complete challenge.
*/
@Expose
private Map<EntityType, Integer> requiredEntities = new EnumMap<>(EntityType.class);
/**
* Boolean that indicate if entities should be removed from world after completion.
*/
@Expose
private boolean removeEntities;
/**
* Radius for searching distance for blocks and entities.
*/
@Expose
private int searchRadius = 10;
}

View File

@ -0,0 +1,207 @@
//
// Created by BONNe
// Copyright - 2019
//
package world.bentobox.challenges.database.object.requirements;
import com.google.gson.annotations.Expose;
import org.eclipse.jdt.annotation.NonNull;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* This class contains all necessary requirements to complete other type challenge.
*/
public class OtherRequirements extends Requirements
{
/**
* Constructor Requirements creates a new Requirements instance.
*/
public OtherRequirements()
{
// Empty constructor
}
// ---------------------------------------------------------------------
// Section: Getters and Setters
// ---------------------------------------------------------------------
/**
* Method OtherRequirements#getRequiredExperience returns the requiredExperience of this object.
*
* @return the requiredExperience (type int) of this object.
*/
public int getRequiredExperience()
{
return requiredExperience;
}
/**
* Method OtherRequirements#setRequiredExperience sets new value for the requiredExperience of this object.
* @param requiredExperience new value for this object.
*
*/
public void setRequiredExperience(int requiredExperience)
{
this.requiredExperience = requiredExperience;
}
/**
* Method OtherRequirements#isTakeExperience returns the takeExperience of this object.
*
* @return the takeExperience (type boolean) of this object.
*/
public boolean isTakeExperience()
{
return takeExperience;
}
/**
* Method OtherRequirements#setTakeExperience sets new value for the takeExperience of this object.
* @param takeExperience new value for this object.
*
*/
public void setTakeExperience(boolean takeExperience)
{
this.takeExperience = takeExperience;
}
/**
* Method OtherRequirements#getRequiredMoney returns the requiredMoney of this object.
*
* @return the requiredMoney (type double) of this object.
*/
public double getRequiredMoney()
{
return requiredMoney;
}
/**
* Method OtherRequirements#setRequiredMoney sets new value for the requiredMoney of this object.
* @param requiredMoney new value for this object.
*
*/
public void setRequiredMoney(double requiredMoney)
{
this.requiredMoney = requiredMoney;
}
/**
* Method OtherRequirements#isTakeMoney returns the takeMoney of this object.
*
* @return the takeMoney (type boolean) of this object.
*/
public boolean isTakeMoney()
{
return takeMoney;
}
/**
* Method OtherRequirements#setTakeMoney sets new value for the takeMoney of this object.
* @param takeMoney new value for this object.
*
*/
public void setTakeMoney(boolean takeMoney)
{
this.takeMoney = takeMoney;
}
/**
* Method OtherRequirements#getRequiredIslandLevel returns the requiredIslandLevel of this object.
*
* @return the requiredIslandLevel (type long) of this object.
*/
public long getRequiredIslandLevel()
{
return requiredIslandLevel;
}
/**
* Method OtherRequirements#setRequiredIslandLevel sets new value for the requiredIslandLevel of this object.
* @param requiredIslandLevel new value for this object.
*
*/
public void setRequiredIslandLevel(long requiredIslandLevel)
{
this.requiredIslandLevel = requiredIslandLevel;
}
// ---------------------------------------------------------------------
// Section: Other methods
// ---------------------------------------------------------------------
/**
* Method Requirements#clone allows to clone Requirements object, to avoid changing content when it is necessary
* to use it.
* @return OtherRequirements clone
*/
@Override
public Requirements clone()
{
OtherRequirements clone = new OtherRequirements();
clone.setRequiredPermissions(new HashSet<>(this.getRequiredPermissions()));
clone.setRequiredExperience(this.requiredExperience);
clone.setTakeExperience(this.takeExperience);
clone.setRequiredMoney(this.requiredMoney);
clone.setTakeMoney(this.takeMoney);
clone.setRequiredIslandLevel(this.requiredIslandLevel);
return clone;
}
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
/**
* Necessary amount of experience for player to complete challenge.
*/
@Expose
private int requiredExperience;
/**
* Should take experience from player.
*/
@Expose
private boolean takeExperience;
/**
* Necessary amount of money in player account to complete challenge. Requires Economy plugin.
*/
@Expose
private double requiredMoney;
/**
* Should take money from player account. Requires Economy plugin.
*/
@Expose
private boolean takeMoney;
/**
* Necessary Island Level from Level Addon
*/
@Expose
private long requiredIslandLevel;
}

View File

@ -0,0 +1,81 @@
//
// Created by BONNe
// Copyright - 2019
//
package world.bentobox.challenges.database.object.requirements;
import com.google.gson.annotations.Expose;
import java.util.HashSet;
import java.util.Set;
/**
* This abstract class allows to define requirements for each challenge.
*/
public abstract class Requirements
{
/**
* Constructor Requirements creates a new Requirements instance.
*/
public Requirements()
{
// Empty Constructor
}
// ---------------------------------------------------------------------
// Section: Getters and Setters
// ---------------------------------------------------------------------
/**
* Method Requirements#getRequiredPermissions returns the requiredPermissions of this object.
*
* @return the requiredPermissions (type Set<String>) of this object.
*/
public Set<String> getRequiredPermissions()
{
return requiredPermissions;
}
/**
* Method Requirements#setRequiredPermissions sets new value for the requiredPermissions of this object.
* @param requiredPermissions new value for this object.
*
*/
public void setRequiredPermissions(Set<String> requiredPermissions)
{
this.requiredPermissions = requiredPermissions;
}
// ---------------------------------------------------------------------
// Section: Other Methods
// ---------------------------------------------------------------------
/**
* Method Requirements#clone allows to clone Requirements object, to avoid changing content when it is necessary
* to use it.
* @return Requirements clone
*/
@Override
public abstract Requirements clone();
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
/**
* This set contains all permission strings that ir required for player to complete challenge.
*/
@Expose
private Set<String> requiredPermissions = new HashSet<>();
}

View File

@ -36,6 +36,9 @@ import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.challenges.ChallengesManager;
import world.bentobox.challenges.database.object.Challenge;
import world.bentobox.challenges.database.object.ChallengeLevel;
import world.bentobox.challenges.database.object.requirements.InventoryRequirements;
import world.bentobox.challenges.database.object.requirements.IslandRequirements;
import world.bentobox.challenges.database.object.requirements.OtherRequirements;
import world.bentobox.challenges.utils.LevelStatus;
import world.bentobox.challenges.utils.Utils;
@ -420,7 +423,7 @@ public abstract class CommonGUI
{
if (challenge.getChallengeType().equals(Challenge.ChallengeType.INVENTORY))
{
if (challenge.isTakeItems())
if (challenge.<InventoryRequirements>getRequirements().isTakeItems())
{
result.add(this.user.getTranslation(
"challenges.gui.challenge-description.warning-items-take"));
@ -431,15 +434,15 @@ public abstract class CommonGUI
result.add(this.user.getTranslation(
"challenges.gui.challenge-description.objects-close-by"));
if (challenge.isRemoveEntities() &&
!challenge.getRequiredEntities().isEmpty())
IslandRequirements requirements = challenge.getRequirements();
if (requirements.isRemoveEntities() && !requirements.getRequiredEntities().isEmpty())
{
result.add(this.user.getTranslation(
"challenges.gui.challenge-description.warning-entities-kill"));
}
if (challenge.isRemoveBlocks() &&
!challenge.getRequiredBlocks().isEmpty())
if (requirements.isRemoveBlocks() && !requirements.getRequiredBlocks().isEmpty())
{
result.add(this.user.getTranslation(
"challenges.gui.challenge-description.warning-blocks-remove"));
@ -479,13 +482,17 @@ public abstract class CommonGUI
{
if (!isCompletedAll)
{
if (challenge.getChallengeType() == Challenge.ChallengeType.OTHER)
switch (challenge.getChallengeType())
{
result.addAll(this.getChallengeRequirements(challenge));
}
else
{
result.addAll(this.getChallengeRequiredItems(challenge));
case INVENTORY:
result.addAll(this.getInventoryRequirements(challenge.getRequirements()));
break;
case ISLAND:
result.addAll(this.getIslandRequirements(challenge.getRequirements()));
break;
case OTHER:
result.addAll(this.getOtherRequirements(challenge.getRequirements()));
break;
}
}
@ -659,33 +666,55 @@ public abstract class CommonGUI
/**
* This method returns list of strings that contains basic information about challenge requirements.
* @param challenge which requirements message must be created.
* This method returns list of strings that contains basic information about requirements.
* @param requirements which requirements message must be created.
* @return list of strings that contains requirements message.
*/
private List<String> getChallengeRequirements(Challenge challenge)
private List<String> getOtherRequirements(OtherRequirements requirements)
{
List<String> result = new ArrayList<>();
// Add message about required exp
if (challenge.getRequiredExperience() > 0)
if (requirements.getRequiredExperience() > 0)
{
result.add(this.user.getTranslation("challenges.gui.challenge-description.required-experience",
"[value]", Integer.toString(challenge.getRequiredExperience())));
"[value]", Integer.toString(requirements.getRequiredExperience())));
}
// Add message about required money
if (this.addon.isEconomyProvided() && challenge.getRequiredMoney() > 0)
if (this.addon.isEconomyProvided() && requirements.getRequiredMoney() > 0)
{
result.add(this.user.getTranslation("challenges.gui.challenge-description.required-money",
"[value]", Integer.toString(challenge.getRequiredMoney())));
"[value]", Double.toString(requirements.getRequiredMoney())));
}
// Add message about required island level
if (this.addon.isLevelProvided() && challenge.getRequiredIslandLevel() > 0)
if (this.addon.isLevelProvided() && requirements.getRequiredIslandLevel() > 0)
{
result.add(this.user.getTranslation("challenges.gui.challenge-description.required-island-level",
"[value]", Long.toString(challenge.getRequiredIslandLevel())));
"[value]", Long.toString(requirements.getRequiredIslandLevel())));
}
return result;
}
/**
* This method returns list of strings that contains basic information about requirements.
* @param requirements which requirements message must be created.
* @return list of strings that contains requirements message.
*/
private List<String> getInventoryRequirements(InventoryRequirements requirements)
{
List<String> result = new ArrayList<>();
// Add message about required items
if (!requirements.getRequiredItems().isEmpty())
{
result.add(this.user.getTranslation("challenges.gui.challenge-description.required-items"));
Utils.groupEqualItems(requirements.getRequiredItems()).forEach(itemStack ->
result.addAll(this.generateItemStackDescription(itemStack)));
}
return result;
@ -697,22 +726,11 @@ public abstract class CommonGUI
* @param challenge Challenge which requirement items, entities and blocks must be returned.
* @return List of strings that contains message from challenges.
*/
private List<String> getChallengeRequiredItems(Challenge challenge)
private List<String> getIslandRequirements(IslandRequirements challenge)
{
List<String> result = new ArrayList<>();
// Add message about required items
if (challenge.getChallengeType().equals(Challenge.ChallengeType.INVENTORY) &&
!challenge.getRequiredItems().isEmpty())
{
result.add(this.user.getTranslation("challenges.gui.challenge-description.required-items"));
Utils.groupEqualItems(challenge.getRequiredItems()).forEach(itemStack ->
result.addAll(this.generateItemStackDescription(itemStack)));
}
if (challenge.getChallengeType().equals(Challenge.ChallengeType.ISLAND) &&
(!challenge.getRequiredBlocks().isEmpty() || !challenge.getRequiredEntities().isEmpty()))
if (!challenge.getRequiredBlocks().isEmpty() || !challenge.getRequiredEntities().isEmpty())
{
// Add required blocks
if (!challenge.getRequiredBlocks().isEmpty())

View File

@ -21,6 +21,7 @@ import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.challenges.panel.CommonGUI;
import world.bentobox.challenges.panel.util.ChallengeTypeGUI;
import world.bentobox.challenges.panel.util.ConfirmationGUI;
import world.bentobox.challenges.utils.GuiUtils;
import world.bentobox.challenges.utils.Utils;
@ -251,21 +252,25 @@ public class AdminGUI extends CommonGUI
clickHandler = (panel, user, clickType, slot) -> {
this.getNewUniqueID(challenge -> {
String newName = Utils.getGameMode(this.world) + "_" + challenge;
String newName = Utils.getGameMode(this.world) + "_" + challenge;
new EditChallengeGUI(this.addon,
this.world,
this.user,
this.addon.getChallengesManager().createChallenge(newName),
this.topLabel,
this.permissionPrefix,
this).build();
ChallengeTypeGUI.open(user,
this.addon.getChallengesSettings().getLoreLineLength(),
(type, requirements) -> {
new EditChallengeGUI(this.addon,
this.world,
this.user,
this.addon.getChallengesManager().createChallenge(newName, type, requirements),
this.topLabel,
this.permissionPrefix,
this).build();
});
},
input -> {
String newName = Utils.getGameMode(this.world) + "_" + input;
return !this.addon.getChallengesManager().containsChallenge(newName);
},
this.user.getTranslation("challenges.question.admin.unique-id")
this.user.getTranslation("challenges.gui.questions.admin.unique-id")
);
return true;
@ -296,7 +301,7 @@ public class AdminGUI extends CommonGUI
String newName = Utils.getGameMode(this.world) + "_" + input;
return !this.addon.getChallengesManager().containsLevel(newName);
},
this.user.getTranslation("challenges.question.admin.unique-id")
this.user.getTranslation("challenges.gui.questions.admin.unique-id")
);
return true;

View File

@ -0,0 +1,145 @@
//
// Created by BONNe
// Copyright - 2019
//
package world.bentobox.challenges.panel.util;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import world.bentobox.bentobox.api.panels.Panel;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.challenges.database.object.Challenge;
import world.bentobox.challenges.database.object.requirements.InventoryRequirements;
import world.bentobox.challenges.database.object.requirements.IslandRequirements;
import world.bentobox.challenges.database.object.requirements.OtherRequirements;
import world.bentobox.challenges.database.object.requirements.Requirements;
import world.bentobox.challenges.utils.GuiUtils;
/**
* This class creates GUI that allows to select challenge type.
*/
public class ChallengeTypeGUI
{
/**
* Default constructor that builds gui.
* @param user User who opens GUI.
* @param lineLength Lore line length
* @param consumer Consumer that allows to get clicked type.
*/
private ChallengeTypeGUI(User user, int lineLength, BiConsumer<Challenge.ChallengeType, Requirements> consumer)
{
this.user = user;
this.lineLength = lineLength;
this.consumer = consumer;
}
/**
* This method opens GUI that allows to select challenge type.
* @param user User who opens GUI.
* @param lineLength Lore line length
* @param consumer Consumer that allows to get clicked type.
*/
public static void open(User user, int lineLength, BiConsumer<Challenge.ChallengeType, Requirements> consumer)
{
new ChallengeTypeGUI(user, lineLength, consumer).build();
}
/**
* This method builds GUI that allows to select challenge type.
*/
private void build()
{
PanelBuilder panelBuilder = new PanelBuilder().
user(this.user).
type(Panel.Type.HOPPER).
name(this.user.getTranslation("challenges.gui.title.admin.type-select"));
panelBuilder.item(0, this.getButton(Challenge.ChallengeType.INVENTORY));
panelBuilder.item(1, this.getButton(Challenge.ChallengeType.ISLAND));
panelBuilder.item(2, this.getButton(Challenge.ChallengeType.OTHER));
panelBuilder.build();
}
/**
* Creates ChallengeType button.
* @param type Challenge type which button must be created.
* @return PanelItem button.
*/
private PanelItem getButton(Challenge.ChallengeType type)
{
ItemStack icon;
String name = this.user.getTranslation("challenges.gui.buttons.admin.type." + type.name().toLowerCase());
List<String> description = new ArrayList<>();
description.add(this.user.getTranslation("challenges.gui.descriptions.type." + type.name().toLowerCase()));
PanelItem.ClickHandler clickHandler;
switch (type)
{
case INVENTORY:
icon = new ItemStack(Material.CHEST);
clickHandler = ((panel, user1, clickType, slot) -> {
this.consumer.accept(type, new InventoryRequirements());
return true;
});
break;
case ISLAND:
icon = new ItemStack(Material.GRASS_BLOCK);
clickHandler = ((panel, user1, clickType, slot) -> {
this.consumer.accept(type, new IslandRequirements());
return true;
});
break;
case OTHER:
icon = new ItemStack(Material.EXPERIENCE_BOTTLE);
clickHandler = ((panel, user1, clickType, slot) -> {
this.consumer.accept(type, new OtherRequirements());
return true;
});
break;
default:
return null;
}
return new PanelItemBuilder().
icon(icon).
name(name).
description(GuiUtils.stringSplit(description, this.lineLength)).
clickHandler(clickHandler).
build();
}
// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
/**
* User who runs GUI.
*/
private final User user;
/**
* Lore line max length.
*/
private final int lineLength;
/**
* Consumer that returns Challenge Type.
*/
private final BiConsumer<Challenge.ChallengeType, Requirements> consumer;
}

View File

@ -25,6 +25,9 @@ import world.bentobox.challenges.ChallengesManager;
import world.bentobox.challenges.database.object.Challenge;
import world.bentobox.challenges.database.object.Challenge.ChallengeType;
import world.bentobox.challenges.database.object.ChallengeLevel;
import world.bentobox.challenges.database.object.requirements.InventoryRequirements;
import world.bentobox.challenges.database.object.requirements.IslandRequirements;
import world.bentobox.challenges.database.object.requirements.OtherRequirements;
import world.bentobox.challenges.utils.Utils;
@ -436,25 +439,26 @@ public class TryToComplete
{
if (this.challenge.getChallengeType().equals(ChallengeType.ISLAND))
{
IslandRequirements requirements = this.challenge.getRequirements();
if (result.meetsRequirements &&
this.challenge.isRemoveEntities() &&
!this.challenge.getRequiredEntities().isEmpty())
requirements.isRemoveEntities() &&
!requirements.getRequiredEntities().isEmpty())
{
this.removeEntities(result.entities, result.getFactor());
}
if (result.meetsRequirements &&
this.challenge.isRemoveBlocks() &&
!this.challenge.getRequiredBlocks().isEmpty())
requirements.isRemoveBlocks() &&
!requirements.getRequiredBlocks().isEmpty())
{
this.removeBlocks(result.blocks, result.getFactor());
}
}
else if (this.challenge.getChallengeType().equals(ChallengeType.INVENTORY))
{
// If remove items, then remove them
if (this.challenge.isTakeItems())
if (this.getInventoryRequirements().isTakeItems())
{
int sumEverything = result.requiredItems.stream().
mapToInt(itemStack -> itemStack.getAmount() * result.getFactor()).
@ -477,17 +481,19 @@ public class TryToComplete
}
else if (this.challenge.getChallengeType().equals(ChallengeType.OTHER))
{
if (this.addon.isEconomyProvided() && this.challenge.isTakeMoney())
OtherRequirements requirements = this.challenge.getRequirements();
if (this.addon.isEconomyProvided() && requirements.isTakeMoney())
{
this.addon.getEconomyProvider().withdraw(this.user, this.challenge.getRequiredMoney());
this.addon.getEconomyProvider().withdraw(this.user, requirements.getRequiredMoney());
}
if (this.challenge.isTakeExperience() &&
if (requirements.isTakeExperience() &&
this.user.getPlayer().getGameMode() != GameMode.CREATIVE)
{
// Cannot take anything from creative game mode.
this.user.getPlayer().setTotalExperience(
this.user.getPlayer().getTotalExperience() - this.challenge.getRequiredExperience());
this.user.getPlayer().getTotalExperience() - requirements.getRequiredExperience());
}
}
}
@ -603,8 +609,8 @@ public class TryToComplete
*/
private boolean checkPermissions()
{
return this.challenge.getRequiredPermissions().isEmpty() ||
this.challenge.getRequiredPermissions().stream().allMatch(s -> this.user.hasPermission(s));
return this.challenge.getRequirements().getRequiredPermissions().isEmpty() ||
this.challenge.getRequirements().getRequiredPermissions().stream().allMatch(s -> this.user.hasPermission(s));
}
@ -714,7 +720,7 @@ public class TryToComplete
// Players in creative game mode has got all items. No point to search for them.
if (this.user.getPlayer().getGameMode() != GameMode.CREATIVE)
{
requiredItems = Utils.groupEqualItems(this.challenge.getRequiredItems());
requiredItems = Utils.groupEqualItems(this.getInventoryRequirements().getRequiredItems());
// Check if all required items are in players inventory.
for (ItemStack required : requiredItems)
@ -849,9 +855,11 @@ public class TryToComplete
// range. In this situation use island range.
int distance = this.addon.getPlugin().getIWM().getIslandDistance(this.world);
if (this.challenge.getSearchRadius() < distance + 1)
IslandRequirements requirements = this.challenge.getRequirements();
if (requirements.getSearchRadius() < distance + 1)
{
distance = this.challenge.getSearchRadius();
distance = requirements.getSearchRadius();
}
boundingBox.expand(distance);
@ -891,7 +899,7 @@ public class TryToComplete
{
this.addon.logError("BoundingBox is larger than SearchRadius. " +
" | BoundingBox: " + boundingBox.toString() +
" | Search Distance: " + this.challenge.getSearchRadius() +
" | Search Distance: " + requirements.getSearchRadius() +
" | Location: " + this.user.getLocation().toString() +
" | Center: " + island.getCenter().toString() +
" | Range: " + range);
@ -900,12 +908,12 @@ public class TryToComplete
}
}
ChallengeResult result = this.searchForEntities(this.challenge.getRequiredEntities(), factor, boundingBox);
ChallengeResult result = this.searchForEntities(requirements.getRequiredEntities(), factor, boundingBox);
if (result.isMeetsRequirements() && !this.challenge.getRequiredBlocks().isEmpty())
if (result.isMeetsRequirements() && !requirements.getRequiredBlocks().isEmpty())
{
// Search for items only if entities found
result = this.searchForBlocks(this.challenge.getRequiredBlocks(), result.getFactor(), boundingBox);
result = this.searchForBlocks(requirements.getRequiredBlocks(), result.getFactor(), boundingBox);
}
return result;
@ -991,7 +999,9 @@ public class TryToComplete
return new ChallengeResult().setMeetsRequirements().setCompleteFactor(factor).setBlockQueue(blockFromWorld);
}
this.user.sendMessage("challenges.errors.not-close-enough", "[number]", String.valueOf(this.challenge.getSearchRadius()));
this.user.sendMessage("challenges.errors.not-close-enough",
"[number]",
String.valueOf(this.getIslandRequirements().getSearchRadius()));
blocks.forEach((k, v) -> user.sendMessage("challenges.errors.you-still-need",
"[amount]", String.valueOf(v),
@ -1094,7 +1104,7 @@ public class TryToComplete
*/
private void removeBlocks(Queue<Block> blockQueue, int factor)
{
Map<Material, Integer> blocks = new EnumMap<>(this.challenge.getRequiredBlocks());
Map<Material, Integer> blocks = new EnumMap<>(this.getIslandRequirements().getRequiredBlocks());
// Increase required blocks by factor.
blocks.entrySet().forEach(entry -> entry.setValue(entry.getValue() * factor));
@ -1118,8 +1128,8 @@ public class TryToComplete
*/
private void removeEntities(Queue<Entity> entityQueue, int factor)
{
Map<EntityType, Integer> entities = this.challenge.getRequiredEntities().isEmpty() ?
new EnumMap<>(EntityType.class) : new EnumMap<>(this.challenge.getRequiredEntities());
Map<EntityType, Integer> entities = this.getIslandRequirements().getRequiredEntities().isEmpty() ?
new EnumMap<>(EntityType.class) : new EnumMap<>(this.getIslandRequirements().getRequiredEntities());
// Increase required entities by factor.
entities.entrySet().forEach(entry -> entry.setValue(entry.getValue() * factor));
@ -1148,59 +1158,61 @@ public class TryToComplete
*/
private ChallengeResult checkOthers(int factor)
{
if (!this.addon.isLevelProvided() &&
this.challenge.getRequiredIslandLevel() != 0)
OtherRequirements requirements = this.getOtherRequirements();
if (!this.addon.isLevelProvided() &&
requirements.getRequiredIslandLevel() != 0)
{
this.user.sendMessage("challenges.errors.missing-addon");
}
else if (!this.addon.isEconomyProvided() &&
this.challenge.getRequiredMoney() != 0)
else if (!this.addon.isEconomyProvided() &&
requirements.getRequiredMoney() != 0)
{
this.user.sendMessage("challenges.errors.missing-addon");
}
else if (this.addon.isEconomyProvided() && this.challenge.getRequiredMoney() < 0)
else if (this.addon.isEconomyProvided() && requirements.getRequiredMoney() < 0)
{
this.user.sendMessage("challenges.errors.incorrect");
}
else if (this.addon.isEconomyProvided() &&
!this.addon.getEconomyProvider().has(this.user, this.challenge.getRequiredMoney()))
!this.addon.getEconomyProvider().has(this.user, requirements.getRequiredMoney()))
{
this.user.sendMessage("challenges.errors.not-enough-money",
"[value]",
Integer.toString(this.challenge.getRequiredMoney()));
Double.toString(requirements.getRequiredMoney()));
}
else if (this.challenge.getRequiredExperience() < 0)
else if (requirements.getRequiredExperience() < 0)
{
this.user.sendMessage("challenges.errors.incorrect");
}
else if (this.user.getPlayer().getTotalExperience() < this.challenge.getRequiredExperience() &&
else if (this.user.getPlayer().getTotalExperience() < requirements.getRequiredExperience() &&
this.user.getPlayer().getGameMode() != GameMode.CREATIVE)
{
// Players in creative gamemode has infinite amount of EXP.
this.user.sendMessage("challenges.errors.not-enough-experience",
"[value]",
Integer.toString(this.challenge.getRequiredExperience()));
Integer.toString(requirements.getRequiredExperience()));
}
else if (this.addon.isLevelProvided() &&
this.addon.getLevelAddon().getIslandLevel(this.world, this.user.getUniqueId()) < this.challenge.getRequiredIslandLevel())
this.addon.getLevelAddon().getIslandLevel(this.world, this.user.getUniqueId()) < requirements.getRequiredIslandLevel())
{
this.user.sendMessage("challenges.errors.island-level",
TextVariables.NUMBER,
String.valueOf(this.challenge.getRequiredIslandLevel()));
String.valueOf(requirements.getRequiredIslandLevel()));
}
else
{
// calculate factor
if (this.addon.isEconomyProvided() && this.challenge.isTakeMoney())
if (this.addon.isEconomyProvided() && requirements.isTakeMoney())
{
factor = Math.min(factor, (int) this.addon.getEconomyProvider().getBalance(this.user) / this.challenge.getRequiredMoney());
factor = Math.min(factor, (int) (this.addon.getEconomyProvider().getBalance(this.user) / requirements.getRequiredMoney()));
}
if (this.challenge.getRequiredExperience() > 0 && this.challenge.isTakeExperience())
if (requirements.getRequiredExperience() > 0 && requirements.isTakeExperience())
{
factor = Math.min(factor, this.user.getPlayer().getTotalExperience() / this.challenge.getRequiredExperience());
factor = Math.min(factor, this.user.getPlayer().getTotalExperience() / requirements.getRequiredExperience());
}
return new ChallengeResult().setMeetsRequirements().setCompleteFactor(factor);
@ -1256,6 +1268,41 @@ public class TryToComplete
}
// ---------------------------------------------------------------------
// Section: Simple getter methods
// ---------------------------------------------------------------------
/**
* This is simple cast method. Easier access to IslandRequirements.
* @return Island Requirements
*/
private IslandRequirements getIslandRequirements()
{
return this.challenge.getRequirements();
}
/**
* This is simple cast method. Easier access to InventoryRequirements.
* @return Inventory Requirements
*/
private InventoryRequirements getInventoryRequirements()
{
return this.challenge.getRequirements();
}
/**
* This is simple cast method. Easier access to OtherRequirements.
* @return Other Requirements
*/
private OtherRequirements getOtherRequirements()
{
return this.challenge.getRequirements();
}
// ---------------------------------------------------------------------
// Section: Private classes
// ---------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

View File

@ -73,6 +73,8 @@ challenges:
lore-add: '&aAdd Lore Element'
lore-remove: '&aRemove Lore Element'
lore-edit: '&aEdit Lore'
type-select: "&aChoose Challenge Type"
challenges: '&6Challenges'
game-modes: '&6Choose GameMode'
@ -93,7 +95,6 @@ challenges:
requirements: 'Requirements'
rewards: 'Rewards'
challenges: 'Challenges'
type: 'Challenge Type'
deployment: 'Deployment'
icon: 'Icon'
locked-icon: 'Locked Icon'
@ -173,6 +174,11 @@ challenges:
library: 'Web Library'
download: 'Download Libraries'
type:
island: '&6Island Type'
inventory: '&6Inventory Type'
other: '&6Other Type'
next: 'Next'
previous: 'Previous'
return: 'Return'
@ -210,7 +216,6 @@ challenges:
description: 'Allows to edit description.'
order: 'Allows to change order number.'
environment: 'Allows to change environment where challenge operates.'
type: 'Allows change challenge type. Each type has their own requirements.'
remove-on-complete: 'Allows to remove challenge from player GUI after it is completed.'
name-challenge: 'Allows to change challenge display name.'
name-level: 'Allows to change level display name.'
@ -316,9 +321,9 @@ challenges:
enabled: 'Active'
disabled: 'Disabled'
type:
island: '- Island Type:| (allows to require blocks or mobs around player)'
inventory: '- Inventory Type:| (allows to require items in players inventory)'
other: '- Other Type:| (allows to require things from other plugins/addons)'
island: '&aallows to require blocks or mobs around player'
inventory: '&aallows to require items in players inventory'
other: '&aallows to require things from other plugins/addons'
the-end: '- The End'
nether: '- Nether'
normal: '- Overworld'