Merge develop into master

This commit is contained in:
BONNe 2019-06-12 23:01:06 +03:00
commit 4d9f817be6
25 changed files with 1366 additions and 702 deletions

View File

@ -7,7 +7,7 @@ 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.7.0**, and you can download it from [Release tab](https://github.com/BentoBoxWorld/Challenges/releases)
Latest official **Beta Release is 0.7.5**, and you can download it from [Release tab](https://github.com/BentoBoxWorld/Challenges/releases)
Or you can try **nightly builds** where you can check and test new features that will be implemented in next release from [Jenkins Server](https://ci.codemc.org/job/BentoBoxWorld/job/Challenges/lastStableBuild/).
@ -29,11 +29,11 @@ There exist also some default challenges, which importing also are available via
## Compatibility
- [x] BentoBox - 1.4.0 version
- [x] BSkyBlock - 1.4.0 version
- [x] AcidIsland - 1.4.0 version
- [x] SkyGrid - 1.4.0 version
- [x] CaveBlock - 1.4.0 version
- [x] BentoBox - 1.5.0 version
- [x] BSkyBlock - 1.5.0 version
- [x] AcidIsland - 1.5.0 version
- [x] SkyGrid - 1.5.0 version
- [x] CaveBlock - 1.5.0 version
## Config.yml

22
pom.xml
View File

@ -36,13 +36,13 @@
<powermock.version>1.7.4</powermock.version>
<!-- More visible way how to change dependency versions -->
<spigot.version>1.13.2-R0.1-SNAPSHOT</spigot.version>
<bentobox.version>1.4.0</bentobox.version>
<bentobox.version>1.5.0</bentobox.version>
<level.version>1.4.0</level.version>
<vault.version>68f14ec</vault.version>
<!-- Revision variable removes warning about dynamic version -->
<revision>${build.version}-SNAPSHOT</revision>
<!-- This allows to change between versions and snapshots. -->
<build.version>0.7.0</build.version>
<build.version>0.7.5</build.version>
<build.number>-LOCAL</build.number>
</properties>
@ -93,9 +93,17 @@
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots</url>
</repository>
<repository>
<id>spigotmc-public</id>
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
</repository>
<repository>
<id>codemc-repo</id>
<url>https://repo.codemc.org/repository/maven-releases/</url>
<url>https://repo.codemc.org/repository/maven-public/</url>
</repository>
<repository>
<id>codemc-nms</id>
<url>https://repo.codemc.org/repository/nms/</url>
</repository>
<!--Vault Repo is down.-->
<!--<repository>-->
@ -169,6 +177,14 @@
</dependencies>
<build>
<!-- By default ${revision} is ${build.version}-SNAPSHOT -->
<!-- If GIT_BRANCH variable is set to origin/master, then it will be only ${build.version}. -->
<!-- By default ${build.number} is -LOCAL. -->
<!-- If the BUILD_NUMBER variable is set, then it will be -b[number]. -->
<!-- If GIT_BRANCH variable is set to origin/master, then it will be the empty string. -->
<finalName>${project.name}-${revision}${build.number}</finalName>
<defaultGoal>clean package</defaultGoal>
<resources>
<resource>

View File

@ -88,6 +88,14 @@ public class ChallengesAddon extends Addon {
new Flag.Builder("CHALLENGES_ISLAND_PROTECTION", Material.COMMAND_BLOCK).defaultRank(RanksManager.VISITOR_RANK).build();
/**
* This ir ugly way how to fix comparability issues between 1.13 and 1.14 versions.
* @deprecated Should be removed as soon as 1.13 support are dropped down.
*/
@Deprecated
public static final Material SIGN_MATERIAL = Bukkit.getBukkitVersion().startsWith("1.13") ? Material.getMaterial("SIGN") : Material.getMaterial("OAK_SIGN");
// ---------------------------------------------------------------------
// Section: Methods
// ---------------------------------------------------------------------
@ -212,6 +220,16 @@ public class ChallengesAddon extends Addon {
this.registerRequestHandler(new LevelDataRequestHandler(this));
this.registerRequestHandler(new CompletedChallengesRequestHandler(this));
if (this.settings.getAutoSaveTimer() > 0)
{
this.getPlugin().getServer().getScheduler().runTaskTimerAsynchronously(
this.getPlugin(),
bukkitTask -> ChallengesAddon.this.challengesManager.save(),
this.settings.getAutoSaveTimer() * 60 * 20,
this.settings.getAutoSaveTimer() * 60 * 20
);
}
} else {
this.logError("Challenges could not hook into AcidIsland or BSkyBlock so will not do anything!");
this.setState(State.DISABLED);

View File

@ -8,7 +8,6 @@ import java.nio.file.Files;
import java.util.*;
import java.util.stream.Collectors;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.configuration.ConfigurationSection;
@ -16,10 +15,8 @@ import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.database.json.adapters.*;
import world.bentobox.bentobox.database.json.BentoboxTypeAdapterFactory;
import world.bentobox.bentobox.database.objects.DataObject;
import world.bentobox.bentobox.util.ItemParser;
import world.bentobox.challenges.database.object.ChallengeLevel;
@ -431,11 +428,7 @@ public class ChallengesImportManager
{
GsonBuilder builder = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().enableComplexMapKeySerialization();
// Register adapters
builder.registerTypeAdapter(Location.class, new LocationAdapter()) ;
builder.registerTypeAdapter(World.class, new WorldAdapter());
builder.registerTypeAdapter(Flag.class, new FlagAdapter(addon.getPlugin()));
builder.registerTypeAdapter(PotionEffectType.class, new PotionEffectTypeAdapter());
builder.registerTypeAdapter(ItemStack.class, new ItemStackTypeAdapter());
builder.registerTypeAdapterFactory(new BentoboxTypeAdapterFactory(addon.getPlugin()));
// Keep null in the database
builder.serializeNulls();
// Allow characters like < or > without escaping them

View File

@ -175,7 +175,7 @@ public class ChallengesManager
* @param challenge Challenge that must be loaded.
* @return true if successful
*/
private void loadChallenge(Challenge challenge)
private void loadChallenge(@NonNull Challenge challenge)
{
this.loadChallenge(challenge, true, null, true);
}
@ -190,11 +190,17 @@ public class ChallengesManager
* @param silent - if true, no messages are sent to user
* @return - true if imported
*/
public boolean loadChallenge(Challenge challenge,
public boolean loadChallenge(@NonNull Challenge challenge,
boolean overwrite,
User user,
boolean silent)
{
if (challenge == null)
{
this.addon.logError("Tried to load NULL element from Database. One challenge is broken and will not work.");
return false;
}
if (this.challengeCacheData.containsKey(challenge.getUniqueId()))
{
if (!overwrite)
@ -235,7 +241,7 @@ public class ChallengesManager
*
* @param level the challenge level
*/
private void loadLevel(ChallengeLevel level)
private void loadLevel(@NonNull ChallengeLevel level)
{
this.loadLevel(level, true, null, true);
}
@ -250,8 +256,14 @@ public class ChallengesManager
* @param silent of type boolean that indicate if message to user must be sent.
* @return boolean that indicate about load status.
*/
public boolean loadLevel(ChallengeLevel level, boolean overwrite, User user, boolean silent)
public boolean loadLevel(@NonNull ChallengeLevel level, boolean overwrite, User user, boolean silent)
{
if (level == null)
{
this.addon.logError("Tried to load NULL element from Database. One level is broken and will not work.");
return false;
}
if (!this.isValidLevel(level))
{
if (user != null)
@ -306,7 +318,7 @@ public class ChallengesManager
* This method stores PlayerData into local cache.
* @param playerData ChallengesPlayerData that must be loaded.
*/
private void loadPlayerData(ChallengesPlayerData playerData)
private void loadPlayerData(@NonNull ChallengesPlayerData playerData)
{
try
{
@ -352,7 +364,7 @@ public class ChallengesManager
* @param level that must be validated
* @return true ir level is valid, otherwise false.
*/
private boolean isValidLevel(ChallengeLevel level)
private boolean isValidLevel(@NonNull ChallengeLevel level)
{
if (!this.addon.getPlugin().getIWM().inWorld(Bukkit.getWorld(level.getWorld())))
{
@ -369,6 +381,7 @@ public class ChallengesManager
}
else
{
this.addon.logError("Cannot find " + uniqueID + " challenge for " + level.getUniqueId());
return false;
}
}
@ -398,7 +411,15 @@ public class ChallengesManager
// Load player from database
ChallengesPlayerData data = this.playersDatabase.loadObject(uniqueID);
// Store in cache
this.playerCacheData.put(uniqueID, data);
if (data != null)
{
this.playerCacheData.put(uniqueID, data);
}
else
{
this.addon.logError("Could not load NULL player data object.");
}
}
else
{
@ -410,6 +431,60 @@ public class ChallengesManager
}
}
// ---------------------------------------------------------------------
// Section: Wipe data
// ---------------------------------------------------------------------
/**
* This method removes all challenges addon data from Database.
*/
public void wipeDatabase()
{
this.wipeLevels();
this.wipeChallenges();
this.wipePlayers();
}
/**
* This method collects all data from levels database and removes them.
* Also clears levels cache data.
*/
private void wipeLevels()
{
List<ChallengeLevel> levelList = this.levelDatabase.loadObjects();
levelList.forEach(level -> this.levelDatabase.deleteID(level.getUniqueId()));
this.levelCacheData.clear();
}
/**
* This method collects all data from challenges database and removes them.
* Also clears challenges cache data.
*/
private void wipeChallenges()
{
List<Challenge> challengeList = this.challengeDatabase.loadObjects();
challengeList.forEach(challenge -> this.challengeDatabase.deleteID(challenge.getUniqueId()));
this.challengeCacheData.clear();
}
/**
* This method collects all data from players database and removes them.
* Also clears players cache data.
*/
private void wipePlayers()
{
List<ChallengesPlayerData> playerDataList = this.playersDatabase.loadObjects();
playerDataList.forEach(playerData -> this.playersDatabase.deleteID(playerData.getUniqueId()));
this.playerCacheData.clear();
}
// ---------------------------------------------------------------------
// Section: Saving methods
@ -1194,8 +1269,16 @@ public class ChallengesManager
if (this.challengeDatabase.objectExists(name))
{
Challenge challenge = this.challengeDatabase.loadObject(name);
this.challengeCacheData.put(name, challenge);
return challenge;
if (challenge != null)
{
this.challengeCacheData.put(name, challenge);
return challenge;
}
else
{
this.addon.logError("Tried to load NULL challenge object!");
}
}
}
@ -1221,8 +1304,16 @@ public class ChallengesManager
if (this.challengeDatabase.objectExists(name))
{
Challenge challenge = this.challengeDatabase.loadObject(name);
this.challengeCacheData.put(name, challenge);
return true;
if (challenge != null)
{
this.challengeCacheData.put(name, challenge);
return true;
}
else
{
this.addon.logError("Tried to load NULL challenge object!");
}
}
}
@ -1342,8 +1433,16 @@ public class ChallengesManager
if (this.levelDatabase.objectExists(name))
{
ChallengeLevel level = this.levelDatabase.loadObject(name);
this.levelCacheData.put(name, level);
return level;
if (level != null)
{
this.levelCacheData.put(name, level);
return level;
}
else
{
this.addon.logError("Tried to load NULL level.");
}
}
}
@ -1369,8 +1468,16 @@ public class ChallengesManager
if (this.levelDatabase.objectExists(name))
{
ChallengeLevel level = this.levelDatabase.loadObject(name);
this.levelCacheData.put(name, level);
return true;
if (level != null)
{
this.levelCacheData.put(name, level);
return true;
}
else
{
this.addon.logError("Tried to load NULL level.");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,9 @@
package world.bentobox.challenges.commands;
import java.util.List;
import java.util.Optional;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.challenges.ChallengesAddon;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
@ -19,26 +21,64 @@ public class ChallengesCommand extends CompositeCommand
}
/**
* {@inheritDoc}
*/
@Override
public boolean canExecute(User user, String label, List<String> args)
{
Optional<GameModeAddon> optionalAddon = this.getAddon().getPlugin().getIWM().getAddon(this.getWorld());
if (!optionalAddon.isPresent())
{
// Not a GameMode world.
user.sendMessage("general.errors.wrong-world");
return false;
}
if (!((ChallengesAddon) this.getAddon()).getChallengesManager().hasAnyChallengeData(this.getWorld()))
{
// Do not open gui if there is no challenges.
this.getAddon().getLogger().severe("There are no challenges set up in " + this.getWorld() + "!");
// Show admin better explanation.
if (user.isOp() || user.hasPermission(this.getPermissionPrefix() + ".admin.challenges"))
{
String topLabel = optionalAddon.get().getAdminCommand().orElseGet(this::getParent).getTopLabel();
user.sendMessage("challenges.errors.no-challenges-admin", "[label]", topLabel);
}
else
{
user.sendMessage("challenges.errors.no-challenges");
}
return false;
}
if (this.getPlugin().getIslands().getIsland(this.getWorld(), user.getUniqueId()) == null)
{
// Do not open gui if there is no island for this player.
user.sendMessage("general.errors.no-island");
return false;
}
return true;
}
@Override
public boolean execute(User user, String label, List<String> args)
{
// Open up the challenges GUI
if (user.isPlayer())
{
if (this.getPlugin().getIslands().getIsland(this.getWorld(), user.getUniqueId()) != null)
{
new ChallengesGUI((ChallengesAddon) this.getAddon(),
this.getWorld(),
user,
this.getTopLabel(),
this.getPermissionPrefix()).build();
return true;
}
else
{
user.sendMessage("general.errors.no-island");
return false;
}
new ChallengesGUI((ChallengesAddon) this.getAddon(),
this.getWorld(),
user,
this.getTopLabel(),
this.getPermissionPrefix()).build();
return true;
}
// Show help
showHelp(this, user);
@ -54,5 +94,6 @@ public class ChallengesCommand extends CompositeCommand
this.setDescription("challenges.commands.user.main.description");
new CompleteChallengeCommand(this.getAddon(), this);
this.setOnlyPlayer(true);
}
}

View File

@ -311,7 +311,7 @@ public class Challenge implements DataObject
*/
public ItemStack getIcon()
{
return icon.clone();
return icon !=null ? icon.clone() : new ItemStack(Material.PAPER);
}

View File

@ -22,21 +22,6 @@ public class SaveListener implements Listener
}
/**
* This event listener handles world save event.
* @param e World Save event.
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onWorldSave(WorldSaveEvent e)
{
// Save only for worlds where exist any challenge addon data.
if (this.addon.getChallengesManager().hasAnyChallengeData(e.getWorld()))
{
this.addon.getChallengesManager().save();
}
}
/**
* This event listener handles player kick event.
* If player is kicked, then remove it from player cache data.

View File

@ -110,6 +110,8 @@ public abstract class CommonGUI
protected static final String DELETE = "delete";
protected static final String WIPE = "wipe";
protected static final String EDIT = "edit";
protected static final String ADD = "add";
@ -216,7 +218,7 @@ public abstract class CommonGUI
{
name = this.user.getTranslation("challenges.gui.buttons.next");
description = Collections.emptyList();
icon = new ItemStack(Material.SIGN);
icon = new ItemStack(ChallengesAddon.SIGN_MATERIAL);
clickHandler = (panel, user, clickType, slot) -> {
this.pageIndex++;
this.build();
@ -229,7 +231,7 @@ public abstract class CommonGUI
{
name = this.user.getTranslation("challenges.gui.buttons.previous");
description = Collections.emptyList();
icon = new ItemStack(Material.SIGN);
icon = new ItemStack(ChallengesAddon.SIGN_MATERIAL);
clickHandler = (panel, user, clickType, slot) -> {
this.pageIndex--;
this.build();

View File

@ -58,7 +58,8 @@ public class AdminGUI extends CommonGUI
IMPORT_CHALLENGES,
EDIT_SETTINGS,
DEFAULT_IMPORT_CHALLENGES,
DEFAULT_EXPORT_CHALLENGES
DEFAULT_EXPORT_CHALLENGES,
COMPLETE_WIPE
}
@ -120,6 +121,9 @@ public class AdminGUI extends CommonGUI
// Edit Addon Settings
panelBuilder.item(16, this.createButton(Button.EDIT_SETTINGS));
// Button that deletes everything from challenges addon
panelBuilder.item(34, this.createButton(Button.COMPLETE_WIPE));
panelBuilder.item(44, this.returnButton);
panelBuilder.build();
@ -439,6 +443,30 @@ public class AdminGUI extends CommonGUI
break;
}
case COMPLETE_WIPE:
{
permissionSuffix = WIPE;
name = this.user.getTranslation("challenges.gui.buttons.admin.complete-wipe");
description = this.user.getTranslation("challenges.gui.descriptions.admin.complete-wipe");
icon = new ItemStack(Material.TNT);
clickHandler = (panel, user, clickType, slot) -> {
new ConfirmationGUI(this.user, value -> {
if (value)
{
this.addon.getChallengesManager().wipeDatabase();
this.user.sendMessage("challenges.messages.admin.complete-wipe");
}
this.build();
});
return true;
};
glow = false;
break;
}
default:
// This should never happen.
return null;

View File

@ -604,7 +604,7 @@ public class EditChallengeGUI extends CommonGUI
{
name = this.user.getTranslation("challenges.gui.buttons.admin.required-blocks");
description = new ArrayList<>(this.challenge.getRequiredEntities().size() + 1);
description = new ArrayList<>(this.challenge.getRequiredBlocks().size() + 1);
description.add(this.user.getTranslation("challenges.gui.descriptions.admin.required-blocks"));
for (Map.Entry<Material, Integer> entry : this.challenge.getRequiredBlocks().entrySet())
@ -713,7 +713,7 @@ public class EditChallengeGUI extends CommonGUI
{
name = this.user.getTranslation("challenges.gui.buttons.admin.required-items");
description = new ArrayList<>(this.challenge.getRequiredEntities().size() + 1);
description = new ArrayList<>(this.challenge.getRequiredItems().size() + 1);
description.add(this.user.getTranslation("challenges.gui.descriptions.admin.required-items"));
for (ItemStack itemStack : this.challenge.getRequiredItems())
@ -847,7 +847,7 @@ public class EditChallengeGUI extends CommonGUI
description = new ArrayList<>(2);
description.add(this.user.getTranslation("challenges.gui.descriptions.admin.required-money"));
description.add(this.user.getTranslation("challenges.gui.descriptions.current-value",
"[value]", Long.toString(this.challenge.getRequiredIslandLevel())));
"[value]", Long.toString(this.challenge.getRequiredMoney())));
icon = new ItemStack(this.addon.isEconomyProvided() ? Material.GOLD_INGOT : Material.BARRIER);
clickHandler = (panel, user, clickType, slot) -> {

View File

@ -466,7 +466,7 @@ public class EditSettingsGUI extends CommonGUI
this.user.getTranslation("challenges.gui.descriptions.enabled") :
this.user.getTranslation("challenges.gui.descriptions.disabled")));
name = this.user.getTranslation("challenges.gui.buttons.admin.title-enable");
icon = new ItemStack(Material.SIGN);
icon = new ItemStack(ChallengesAddon.SIGN_MATERIAL);
clickHandler = (panel, user1, clickType, i) -> {
this.settings.setShowCompletionTitle(!this.settings.isShowCompletionTitle());

View File

@ -111,6 +111,7 @@ public class ManageBlocksGUI extends CommonGUI
*/
private PanelItem createButton(Button button)
{
int lineLength = this.addon.getChallengesSettings().getLoreLineLength();
PanelItemBuilder builder = new PanelItemBuilder();
switch (button)
@ -120,11 +121,13 @@ public class ManageBlocksGUI extends CommonGUI
builder.icon(Material.BUCKET);
builder.clickHandler((panel, user1, clickType, slot) -> {
new SelectBlocksGUI(this.user, new HashSet<>(this.materialList), (status, material) -> {
new SelectBlocksGUI(this.user, new HashSet<>(this.materialList), (status, materials) -> {
if (status)
{
this.materialMap.put(material, 1);
this.materialList.add(material);
materials.forEach(material -> {
this.materialMap.put(material, 1);
this.materialList.add(material);
});
}
this.build();
@ -134,7 +137,7 @@ public class ManageBlocksGUI extends CommonGUI
break;
case REMOVE:
builder.name(this.user.getTranslation("challenges.gui.buttons.admin.remove-selected"));
builder.description(this.user.getTranslation("challenges.gui.descriptions.admin.remove-selected"));
builder.description(GuiUtils.stringSplit(this.user.getTranslation("challenges.gui.descriptions.admin.remove-selected"), lineLength));
builder.icon(Material.LAVA_BUCKET);
builder.clickHandler((panel, user1, clickType, slot) -> {
this.materialMap.keySet().removeAll(this.selectedMaterials);

View File

@ -111,6 +111,7 @@ public class ManageEntitiesGUI extends CommonGUI
*/
private PanelItem createButton(Button button)
{
int lineLength = this.addon.getChallengesSettings().getLoreLineLength();
PanelItemBuilder builder = new PanelItemBuilder();
switch (button)
@ -119,14 +120,13 @@ public class ManageEntitiesGUI extends CommonGUI
builder.name(this.user.getTranslation("challenges.gui.buttons.admin.add"));
builder.icon(Material.BUCKET);
builder.clickHandler((panel, user1, clickType, slot) -> {
new SelectEntityGUI(this.user, Collections.emptySet(), this.asEggs, (status, entity) -> {
new SelectEntityGUI(this.user, this.requiredEntities.keySet(), this.asEggs, (status, entities) -> {
if (status)
{
if (!this.requiredEntities.containsKey(entity))
{
entities.forEach(entity -> {
this.requiredEntities.put(entity, 1);
this.entityList.add(entity);
}
});
}
this.build();
@ -136,7 +136,7 @@ public class ManageEntitiesGUI extends CommonGUI
break;
case REMOVE:
builder.name(this.user.getTranslation("challenges.gui.buttons.admin.remove-selected"));
builder.description(this.user.getTranslation("challenges.gui.descriptions.admin.remove-selected"));
builder.description(GuiUtils.stringSplit(this.user.getTranslation("challenges.gui.descriptions.admin.remove-selected"), lineLength));
builder.icon(Material.LAVA_BUCKET);
builder.clickHandler((panel, user1, clickType, slot) -> {
this.requiredEntities.keySet().removeAll(this.selectedEntities);
@ -147,7 +147,7 @@ public class ManageEntitiesGUI extends CommonGUI
break;
case SWITCH:
builder.name(this.user.getTranslation("challenges.gui.buttons.admin.show-eggs"));
builder.description(this.user.getTranslation("challenges.gui.descriptions.admin.show-eggs"));
builder.description(GuiUtils.stringSplit(this.user.getTranslation("challenges.gui.descriptions.admin.show-eggs"), lineLength));
builder.icon(this.asEggs ? Material.EGG : Material.PLAYER_HEAD);
builder.clickHandler((panel, user1, clickType, slot) -> {
this.asEggs = !this.asEggs;

View File

@ -162,7 +162,7 @@ public class ChallengesGUI extends CommonGUI
if (this.freeChallengeIndex > 0)
{
panelBuilder.item(index++, new PanelItemBuilder().
icon(Material.SIGN).
icon(ChallengesAddon.SIGN_MATERIAL).
name(this.user.getTranslation("challenges.gui.buttons.previous")).
clickHandler((panel, user1, clickType, slot) -> {
this.freeChallengeIndex--;
@ -186,7 +186,7 @@ public class ChallengesGUI extends CommonGUI
else if (currentIndex < freeChallengesCount)
{
panelBuilder.item(index, new PanelItemBuilder().
icon(Material.SIGN).
icon(ChallengesAddon.SIGN_MATERIAL).
name(this.user.getTranslation("challenges.gui.buttons.next")).
clickHandler((panel, user1, clickType, slot) -> {
this.freeChallengeIndex++;
@ -232,7 +232,7 @@ public class ChallengesGUI extends CommonGUI
if (this.pageIndex > 0)
{
panelBuilder.item(index++, new PanelItemBuilder().
icon(Material.SIGN).
icon(ChallengesAddon.SIGN_MATERIAL).
name(this.user.getTranslation("challenges.gui.buttons.previous")).
clickHandler((panel, user1, clickType, slot) -> {
this.pageIndex--;
@ -256,7 +256,7 @@ public class ChallengesGUI extends CommonGUI
else if (currentIndex < challengesCount)
{
panelBuilder.item(index, new PanelItemBuilder().
icon(Material.SIGN).
icon(ChallengesAddon.SIGN_MATERIAL).
name(this.user.getTranslation("challenges.gui.buttons.next")).
clickHandler((panel, user1, clickType, slot) -> {
this.pageIndex++;
@ -293,7 +293,7 @@ public class ChallengesGUI extends CommonGUI
if (this.levelIndex > 0)
{
panelBuilder.item(index++, new PanelItemBuilder().
icon(Material.SIGN).
icon(ChallengesAddon.SIGN_MATERIAL).
name(this.user.getTranslation("challenges.gui.buttons.previous")).
clickHandler((panel, user1, clickType, slot) -> {
this.levelIndex--;
@ -317,7 +317,7 @@ public class ChallengesGUI extends CommonGUI
else if (currentIndex < levelCounts)
{
panelBuilder.item(index, new PanelItemBuilder().
icon(Material.SIGN).
icon(ChallengesAddon.SIGN_MATERIAL).
name(this.user.getTranslation("challenges.gui.buttons.next")).
clickHandler((panel, user1, clickType, slot) -> {
this.levelIndex++;

View File

@ -4,16 +4,14 @@ package world.bentobox.challenges.panel.util;
import org.apache.commons.lang.WordUtils;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.function.BiConsumer;
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.ChallengesAddon;
import world.bentobox.challenges.utils.GuiUtils;
@ -23,13 +21,13 @@ import world.bentobox.challenges.utils.GuiUtils;
*/
public class SelectBlocksGUI
{
public SelectBlocksGUI(User user, BiConsumer<Boolean, Material> consumer)
public SelectBlocksGUI(User user, BiConsumer<Boolean, Set<Material>> consumer)
{
this(user, Collections.emptySet(), consumer);
}
public SelectBlocksGUI(User user, Set<Material> excludedMaterial, BiConsumer<Boolean, Material> consumer)
public SelectBlocksGUI(User user, Set<Material> excludedMaterial, BiConsumer<Boolean, Set<Material>> consumer)
{
this.consumer = consumer;
this.user = user;
@ -47,6 +45,7 @@ public class SelectBlocksGUI
excludedMaterial.add(Material.BARRIER);
this.elements = new ArrayList<>();
this.selectedMaterials = new HashSet<>();
for (Material material : Material.values())
{
@ -107,7 +106,7 @@ public class SelectBlocksGUI
index++;
}
panelBuilder.item(4,
panelBuilder.item(3,
new PanelItemBuilder().
icon(Material.RED_STAINED_GLASS_PANE).
name(this.user.getTranslation("challenges.gui.buttons.admin.cancel")).
@ -116,13 +115,31 @@ public class SelectBlocksGUI
return true;
}).build());
List<String> description = new ArrayList<>();
if (!this.selectedMaterials.isEmpty())
{
description.add(this.user.getTranslation("challenges.gui.descriptions.admin.selected") + ":");
this.selectedMaterials.forEach(material -> description.add(" - " + material.name()));
}
panelBuilder.item(5,
new PanelItemBuilder().
icon(Material.GREEN_STAINED_GLASS_PANE).
name(this.user.getTranslation("challenges.gui.buttons.admin.accept")).
description(description).
clickHandler( (panel, user1, clickType, slot) -> {
this.consumer.accept(true, this.selectedMaterials);
return true;
}).build());
if (this.elements.size() > MAX_ELEMENTS)
{
// Navigation buttons if necessary
panelBuilder.item(18,
new PanelItemBuilder().
icon(Material.SIGN).
icon(ChallengesAddon.SIGN_MATERIAL).
name(this.user.getTranslation("challenges.gui.buttons.previous")).
clickHandler((panel, user1, clickType, slot) -> {
this.build(correctPage - 1);
@ -131,7 +148,7 @@ public class SelectBlocksGUI
panelBuilder.item(26,
new PanelItemBuilder().
icon(Material.SIGN).
icon(ChallengesAddon.SIGN_MATERIAL).
name(this.user.getTranslation("challenges.gui.buttons.next")).
clickHandler((panel, user1, clickType, slot) -> {
this.build(correctPage + 1);
@ -164,9 +181,22 @@ public class SelectBlocksGUI
return new PanelItemBuilder().
name(WordUtils.capitalize(material.name().toLowerCase().replace("_", " "))).
description(this.selectedMaterials.contains(material) ?
this.user.getTranslation("challenges.gui.descriptions.admin.selected") : "").
icon(itemStack).
clickHandler((panel, user1, clickType, slot) -> {
this.consumer.accept(true, material);
if (clickType.isRightClick())
{
if (!this.selectedMaterials.add(material))
{
this.selectedMaterials.remove(material);
}
}
else
{
this.consumer.accept(true, this.selectedMaterials);
}
return true;
}).
glow(!itemStack.getType().equals(material)).
@ -183,10 +213,15 @@ public class SelectBlocksGUI
*/
private List<Material> elements;
/**
* Set that contains selected materials.
*/
private Set<Material> selectedMaterials;
/**
* This variable stores consumer.
*/
private BiConsumer<Boolean, Material> consumer;
private BiConsumer<Boolean, Set<Material>> consumer;
/**
* User who runs GUI.

View File

@ -11,6 +11,7 @@ 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.ChallengesAddon;
import world.bentobox.challenges.database.object.Challenge;
import world.bentobox.challenges.utils.GuiUtils;
@ -75,7 +76,7 @@ public class SelectChallengeGUI
panelBuilder.item(18,
new PanelItemBuilder().
icon(Material.SIGN).
icon(ChallengesAddon.SIGN_MATERIAL).
name(this.user.getTranslation("challenges.gui.buttons.previous")).
clickHandler((panel, user1, clickType, slot) -> {
this.build(correctPage - 1);
@ -84,7 +85,7 @@ public class SelectChallengeGUI
panelBuilder.item(26,
new PanelItemBuilder().
icon(Material.SIGN).
icon(ChallengesAddon.SIGN_MATERIAL).
name(this.user.getTranslation("challenges.gui.buttons.next")).
clickHandler((panel, user1, clickType, slot) -> {
this.build(correctPage + 1);

View File

@ -12,6 +12,7 @@ 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.ChallengesAddon;
import world.bentobox.challenges.utils.GuiUtils;
@ -20,19 +21,20 @@ import world.bentobox.challenges.utils.GuiUtils;
*/
public class SelectEntityGUI
{
public SelectEntityGUI(User user, BiConsumer<Boolean, EntityType> consumer)
public SelectEntityGUI(User user, BiConsumer<Boolean, Set<EntityType>> consumer)
{
this(user, Collections.emptySet(), true, consumer);
}
public SelectEntityGUI(User user, Set<EntityType> excludedEntities, boolean asEggs, BiConsumer<Boolean, EntityType> consumer)
public SelectEntityGUI(User user, Set<EntityType> excludedEntities, boolean asEggs, BiConsumer<Boolean, Set<EntityType>> consumer)
{
this.consumer = consumer;
this.user = user;
this.asEggs = asEggs;
this.entities = new ArrayList<>(EntityType.values().length);
this.selectedEntities = new HashSet<>(EntityType.values().length);
for (EntityType entityType : EntityType.values())
{
@ -81,7 +83,7 @@ public class SelectEntityGUI
correctPage = pageIndex;
}
panelBuilder.item(4,
panelBuilder.item(3,
new PanelItemBuilder().
icon(Material.RED_STAINED_GLASS_PANE).
name(this.user.getTranslation("challenges.gui.buttons.admin.cancel")).
@ -90,13 +92,30 @@ public class SelectEntityGUI
return true;
}).build());
List<String> description = new ArrayList<>();
if (!this.selectedEntities.isEmpty())
{
description.add(this.user.getTranslation("challenges.gui.descriptions.admin.selected") + ":");
this.selectedEntities.forEach(entity -> description.add(" - " + entity.name()));
}
panelBuilder.item(5,
new PanelItemBuilder().
icon(Material.GREEN_STAINED_GLASS_PANE).
name(this.user.getTranslation("challenges.gui.buttons.admin.accept")).
description(description).
clickHandler( (panel, user1, clickType, slot) -> {
this.consumer.accept(true, this.selectedEntities);
return true;
}).build());
if (this.entities.size() > MAX_ELEMENTS)
{
// Navigation buttons if necessary
panelBuilder.item(18,
new PanelItemBuilder().
icon(Material.SIGN).
icon(ChallengesAddon.SIGN_MATERIAL).
name(this.user.getTranslation("challenges.gui.buttons.previous")).
clickHandler((panel, user1, clickType, slot) -> {
this.build(correctPage - 1);
@ -105,7 +124,7 @@ public class SelectEntityGUI
panelBuilder.item(26,
new PanelItemBuilder().
icon(Material.SIGN).
icon(ChallengesAddon.SIGN_MATERIAL).
name(this.user.getTranslation("challenges.gui.buttons.next")).
clickHandler((panel, user1, clickType, slot) -> {
this.build(correctPage + 1);
@ -156,10 +175,25 @@ public class SelectEntityGUI
return new PanelItemBuilder().
name(WordUtils.capitalize(entity.name().toLowerCase().replace("_", " "))).
icon(itemStack).
description(this.selectedEntities.contains(entity) ?
this.user.getTranslation("challenges.gui.descriptions.admin.selected") : "").
clickHandler((panel, user1, clickType, slot) -> {
this.consumer.accept(true, entity);
if (clickType.isRightClick())
{
if (!this.selectedEntities.add(entity))
{
this.selectedEntities.remove(entity);
}
}
else
{
this.consumer.accept(true, this.selectedEntities);
}
return true;
}).build();
}).
glow(this.selectedEntities.contains(entity)).
build();
}
@ -171,7 +205,12 @@ public class SelectEntityGUI
/**
* This variable stores consumer.
*/
private BiConsumer<Boolean, EntityType> consumer;
private BiConsumer<Boolean, Set<EntityType>> consumer;
/**
* Set that contains selected entities.
*/
private Set<EntityType> selectedEntities;
/**
* User who runs GUI.

View File

@ -162,7 +162,9 @@ public class TryToComplete
this.permissionPrefix = permissionPrefix;
this.user = user;
this.manager = addon.getChallengesManager();
this.challenge = challenge;
// To avoid any modifications that may accure to challenges in current completion
// just clone it.
this.challenge = challenge.clone();
this.topLabel = topLabel;
}
@ -1021,7 +1023,7 @@ public class TryToComplete
// kick garbage collector
blocks.clear();
blocksFound.clear();
requiredMap.clear();
blockFromWorld.clear();
return EMPTY_RESULT;
}
@ -1064,6 +1066,8 @@ public class TryToComplete
// Check if entity is inside challenge bounding box
if (requiredMap.containsKey(entity.getType()))
{
entityQueue.add(entity);
entitiesFound.putIfAbsent(entity.getType(), 1);
entitiesFound.computeIfPresent(entity.getType(), (reqEntity, amount) -> amount + 1);

View File

@ -109,6 +109,10 @@ title:
# Integer that represents how long title will be visible for player.
title-showtime: 70
#
# Long that represents how frequently (in minutes) challenges addon will save data to database.
# If this is set to 0, saving will not happen.
auto-saver: 30
#
# This list stores GameModes in which Challenges addon should not work.
# To disable addon it is necessary to write its name in new line that starts with -. Example:
# disabled-gamemodes:

View File

@ -148,6 +148,7 @@ challenges:
title-showtime: 'Title Show Time'
default-import: 'Import Default Challenges'
default-export: 'Export Existing Challenges'
complete-wipe: 'Wipe Addon Databases'
next: 'Next'
previous: 'Previous'
return: 'Return'
@ -243,6 +244,7 @@ challenges:
title-showtime: 'Allows to modify how long title message will be visible for player.'
default-import: 'Allows to import default challenges.'
default-export: 'Allows to export existing challenges into defaults.json file.'
complete-wipe: 'Allows to completely clear all challenges addon databases. Includes player data!'
current-value: '|&6Current value: [value].'
enabled: 'Active'
disabled: 'Disabled'
@ -309,6 +311,7 @@ challenges:
hit-things: 'Hit things to add them to the list of things required. Right click when done.'
you-added: 'You added one [thing] to the challenge'
challenge-created: '[challenge]&r created!'
complete-wipe: '&cHope you have backups, as you just empty all Challenges Addon databases!'
you-completed-challenge: '&2You completed the [value] &r&2challenge!'
you-repeated-challenge: '&2You repeated the [value] &r&2challenge!'
you-repeated-challenge-multiple: '&2You repeated the [value] &r&2challenge [count] times!'
@ -353,6 +356,7 @@ challenges:
defaults-file-exist: '&cdefaults.json already exists. Use overwrite mode to replace it!'
defaults-file-error: '&cThere was an error while creating defaults.json file! Check console!'
no-challenges: '&cChallenges are not implemented in current world!'
no-challenges-admin: '&cChallenges are not implemented in current world! You should use &5/[label] challenges &cto adding them!'
missing-level: '&cChallenge Level [level] is not defined in database. It may case some errors!'
protection:
flags:

View File

@ -0,0 +1,371 @@
###########################################################################################
# This is a YML file. Be careful when editing. Check your edits in a YAML checker like #
# the one at http://yaml-online-parser.appspot.com #
###########################################################################################
meta:
authors:
- nivcoo
challenges:
commands:
admin:
main:
parameters: ''
description: 'Commande principale Admin. Ouverture du menu.'
import:
description: 'Importer les challenges du challenges.yml|Ce paramètre écrasera vos anciens challenges et levels !'
parameters: '[overwrite]'
reload:
description: 'Recharger les challenges depuis la base de données|Le paramètre hard réinitialisera la connexion à la base de données.'
parameters: '[hard]'
show:
description: 'Cette méthode écrira dans le chat tous les challenges du monde.'
parameters: ''
defaults:
description: 'Cette méthode permet d''afficher les sous commandes pour importer/exporter les challenges par défauts.'
parameters: '[command]'
defaults-import:
description: 'Cette méthode permet d''importer les challenges par défauts.'
parameters: ''
defaults-generate:
description: 'Cette méthode permet d''exporter les challenges dans un fichier default.json.'
parameters: '[overwrite] - permet d''écraser le fichier existant.'
user:
main:
description: 'Cette méthode ouvre le menu des Challenges.'
parameters: ''
complete:
description: 'Cette méthode permet de compléter un challenger sans menu.'
parameters: '<challenge_id> [count]'
gui:
title:
admin:
gui-title: '&aMenu admin des Challenges'
edit-challenge-title: '&aModification Challenge'
edit-level-title: '&aModification Niveau'
settings-title: '&aModification Paramètre'
choose-challenge-title: '&aChoix du Challenge'
choose-level-title: '&aChoix du Niveau'
choose-user-title: '&aChoix du Joueur'
manage-blocks: '&aGestion des Blocs'
manage-entities: '&aGestion des Entités'
confirm-title: '&aConfirmation'
manage-items: '&aGestion des Items'
manage-numbers: '&aGestion des chiffres'
select-block: '&aSelection du Bloc'
select-challenge: '&aSelection du Challenge'
select-entity: '&aSelection de l''Entité'
toggle-environment: '&aChanger l''Environnement'
edit-text-fields: '&aModification du Texte'
challenges: '&aListe des challenges'
game-modes: '&aChoisissez votre mode de jeux'
buttons:
admin:
complete: 'Compléter le challenge d''un joueur'
reset: 'Réinitialiser le challenge d''un joueur'
create-challenge: 'Ajouter un nouveau challenge'
create-level: 'Ajouter un nouveau Niveau'
edit-challenge: 'Modifier un Challenge'
edit-level: 'Modifier un Niveau'
delete-challenge: 'Supprimer un Challenge'
delete-level: 'Supprimer un Niveau'
import: 'Importer les Challenges d''ASkyblock'
settings: 'Modifier les paramètres'
properties: 'Propriétés'
requirements: 'Prérequis'
rewards: 'Récompenses'
challenges: 'Challenges'
type: 'Type de Challenge'
deployment: 'Déploiement'
icon: 'Icône'
locked-icon: 'Icône verrouillée'
description: 'Description'
order: 'Ordre'
environment: 'Environnement'
remove-on-complete: 'Supprimer après l''achèvement'
name: 'Nom visible'
required-entities: 'Entités requises'
remove-entities: 'Tuer des entités'
required-blocks: 'Blocs requis'
remove-blocks: 'Supprimer des blocs'
search-radius: 'Rayon de recherche'
required-permissions: 'Permissions requises'
required-items: 'Items requis'
remove-items: 'Supprimer les Items'
required-experience: 'Experience requise'
remove-experience: 'Supprimer de l''expérience'
required-level: 'Niveau d''island requis'
required-money: 'Monnaies requises'
remove-money: 'Supprimer de la monnaies'
reward-text: 'Message de récompense'
reward-items: 'Items gagnés'
reward-experience: 'Expériences gagnées'
reward-money: 'Monnaies gagnées'
reward-commands: 'Commandes gagnées'
repeatable: 'Répétable'
repeat-count: 'Maximum de répétitions'
repeat-reward-text: 'Message de récompense(s) lors d''une répétition'
repeat-reward-items: 'Récompense(s) lors d''une répétition'
repeat-reward-experience: 'Récompense(s) lors d''une répétition'
repeat-reward-money: 'Récompense(s) lors d''une répétition'
repeat-reward-commands: 'Récompense(s) lors d''une répétition'
waiver-amount: 'Montant de la renonciation'
add-challenge: 'Ajouter un Challenge'
remove-challenge: 'Supprimer un Challenge'
reset-on-new: 'Réinitialiser sur nouvelle île'
broadcast: 'Message de l''achèvement'
remove-completed: 'Supprimer après l''achèvement'
glow: 'Brillant lorsque complété'
free-at-top: 'Les premiers challenges gratuits'
line-length: 'Taille des Lores'
toggle-user-list: 'Liste des joueurs'
remove-selected: 'Supprimer la sélection'
add: 'Ajouter'
show-eggs: 'Changer de mode d''affichage'
accept: 'Accepter'
decline: 'Décliner'
save: 'Sauvegarder'
cancel: 'Annuler'
input: 'Champ d''écriture'
value: 'Valeur'
set: '='
increase: '+'
reduce: '-'
multiply: '*'
clear: 'Vider'
remove-empty: 'Supprimer le vide'
number: '[number]'
level-lore: 'Description du Niveau'
challenge-lore: 'Description du Challenge'
gui-view-mode: 'Afficher tous les Mode de jeux'
gui-mode: 'Menus des Challenges uniquement'
history-store: 'Historique des Challenges'
history-lifespan: 'Durée d''ancienneté de l''historique'
island-store: 'Stockage par île'
default-locked-icon: 'Icône de niveau verrouillé'
input-mode: 'Changer de mode d''entrée'
title-enable: 'Titre d''achèvement'
title-showtime: 'Titre affichant l''heure'
default-import: 'Importer les Challenges par défaut'
default-export: 'Exporter les Challenges existants'
complete-wipe: 'Vider entièrement toute les données'
next: 'Suivant'
previous: 'Précédent'
return: 'Retour'
descriptions:
admin:
save: 'Sauvegarder et retourner au Menus précédent.'
cancel: 'Retourner au Menus précédent. Les changements ne sont pas sauvegardés.'
input: 'Ouvrir l''éditeur de texte.'
set: 'En cliquant sur les chiffres, la valeur devient le chiffre sélectionné.'
increase: 'Augmenter la valeur. En cliquant sur les nombres, vous augmentez la valeur du chiffre sélectionné.'
reduce: 'Réduire la valeur. En cliquant sur les chiffres, vous diminuez la valeur du chiffre sélectionné.'
multiply: 'Multiplier la valeur. En cliquant sur les chiffres, vous multiplier la valeur du chiffre sélectionné.'
import: 'Permet d''importer des challenges ASkyblock.|Un clic droit sur la souris active/désactive l''écrasement des données|Placez le fichier Challenges.yml dans le dossier ./BentoBox/addons/Challenges.'
complete: 'Permet de compléter les Challenges d''un joueur.|Ce joueur ne gagne pas les récompenses.'
reset: 'Permet de réinitialiser les Challenges terminés d''un joueur.|Clic droit activer / désactiver, Réinitialiser toutes les fonctionnalités.'
create-challenge: 'Permet d''ajouter un nouveau Challenge.|Par défaut il est dans la liste des Challenges gratuits.'
create-level: 'Permet d''ajouter un nouveau Niveau.'
edit-challenge: 'Permet de modifier les paramètres du Challenge.'
edit-level: 'Permet de modifier les paramètres du niveau.'
delete-challenge: 'Permet de supprimer un Challenge.'
delete-level: 'Permet de supprimer n''importe quel niveau.'
settings: 'Permet de changer les paramètres d''un Addon.'
properties: 'Permet de modifier les propriétés générales'
requirements: 'Permet de gérer les prérequis'
rewards: 'Permet de modifier les récompenses'
challenges: 'Permet de contrôler le niveau des Challenges (Ajouter / Supprimer).'
deployment: 'Permet aux joueurs de compléter (voir) le Challenge.'
icon-challenge: 'Icône qui sera affichée dans le menu pour ce Challenge.'
icon-level: 'Icône qui sera affichée dans le menu pour ce Niveau.'
locked-icon: 'Icône qui sera affichée dans le menu si le niveau est verrouillé.'
description: 'Permet de modifier la description.'
order: 'Permet de changer le numéro de classification.'
environment: 'Permet de changer l''environnement où le Challenge est effectué.'
type: 'Permet de changer le type de challenge. Chaque type a ses propres prérequis.'
remove-on-complete: 'Permet de supprimer le Challenge dans le menu du joueur une fois celui-ci terminé.'
name-challenge: 'Permet de changer le nom d''affichage du Challenge.'
name-level: 'Permet de changer le nom d''affichage du Niveau.'
required-entities: 'Permet d''ajouter, modifier ou supprimer des entités requises.|Entités:|'
remove-entities: 'Permet de supprimer (tuer) des entités à la fin du Challenge.'
required-blocks: 'Permet d''ajouter, modifier ou supprimer les blocs requis.|Blocs:|'
remove-blocks: 'Permet de supprimer (remplacer par du vide) les blocs à la fin du challenge.'
search-radius: 'Rayon autour de l''emplacement du joueur où les entités et les blocs requis seront recherchés.'
required-permissions: 'Permissions requises pour que le joueur puisse compléter le Challenge.|Permission:'
required-items: 'Objets requis dans l''inventaire du joueur.|Items:'
remove-items: 'Permet de supprimer les objets de l''inventaire du joueur après avoir terminé le Challenge.'
required-experience: 'Permet de définir l''expérience requise pour que le joueur puisse compléter le Challenge.'
remove-experience: 'Permet de supprimer l''expérience requise.'
required-level: 'Permet de définir le niveau d''île requis pour ce challenge.|&cNécessite Level addon.'
required-money: 'Permet de définir l''argent requis sur le compte du joueur.|&cNécessite Vault ou un plugin d''économie.'
remove-money: 'Permet de retirer l''argent requis du compte du joueur.|&cNécessite Vault ou un plugin d''économie.'
reward-text: 'Permet de changer le message qui sera envoyé au joueur après la fin du Challenge.'
reward-items: 'Permet de changer la récompense du premier achèvement.|Items:'
reward-experience: 'Permet de changer la récompense (experience) du premier achèvement.'
reward-money: 'Permet de changer la récompense (monnaie) du premier achèvement.|&cNécessite Vault ou un plugin d''économie.'
reward-commands: 'Permet de changer la récompense (commandes) du premier achèvement.|***Ajouter "[SELF]" signifie que la commande sera exécutée par le joueur. Exemple "/kill"|***Le mot "[player]" sera remplacé par le pseudo du joueur, exemple "/kill [player]" sera remplacé par "/kill BONNe1704"|Commands:'
repeatable: 'Permet de définir si le Challenge est répétable.'
repeat-count: 'Permet de définir le nombre maximal de répétitions. Si la valeur est définie sur 0 ou moins, il n''y a pas de limitation.'
repeat-reward-text: 'Permet de changer le message qui sera envoyé au joueur suite à la répétition du challenge.'
repeat-reward-items: 'Permet de changer les récompenses lors d''une répétition|Items:'
repeat-reward-experience: Permet de changer les récompenses (Expériences) lors d''une répétition'
repeat-reward-money: 'Permet de changer les récompenses (Monnaies) lors d''une répétition|&cNécessite Vault ou un plugin d''économie.'
repeat-reward-commands: 'Permet de changer les récompenses (Commandes) lors d''une répétition|***Ajouter "[SELF]" signifie que la commande sera exécutée par le joueur. Exemple "/kill"|***Le mot "[player]" sera remplacé par le pseudo du joueur, exemple "/kill [player]" sera remplacé par "/kill BONNe1704"|Commands:'
waiver-amount: 'Permet de définir le nombre de Challenges non-obligatoire pour changer de Niveau.'
reward-text-level: 'Permet de changer le message qui sera envoyé au joueur après avoir complété tous les Challenges du Niveau.'
add-challenge: 'Permet d''ajouter un Challenge existant au Niveau actuel.'
remove-challenge: 'Permet de supprimer un Challenge du Niveau actuel.'
reset-on-new: 'Activer/Désactiver, la réinitialisation de tous les challenges du joueur lorsqu''il recommence son île ou qu''il a quitté/été kické de son île.'
broadcast: 'Activer/Désactiver le message global lorsqu''un joueur complète pour la première fois un Challenge.'
remove-completed: 'Activer/Désactiver que les challenges complété et non répétable soit cachés.'
glow: 'Activer/Désactiver l''effet de brillance sur un Challenge complété.'
free-at-top: 'Permet de changer l''emplacement des Challenges gratuits. “True” signifie que les Challenges seront les premiers, sinon ils seront les derniers.'
line-length: 'Permet de modifier la longueur maximale (ligne) de la description de l''objet. N''affectera pas les objets stockés.'
toggle-user-list: 'Basculer vers une liste de joueurs différente.'
mode-online: 'Joueurs actuellement en ligne.'
mode-in-world: 'Les joueurs qui sont dans le monde GameMode.'
mode-with-island: 'Les joueurs qui ont une île dans GameMode.'
selected: 'Sélectionné'
remove-selected: 'Supprimer les éléments sélectionnés.|Vous pouvez sélectionner des éléments avec le bouton droit de la souris.'
show-eggs: 'Basculer la vue d''entité entre le mode Egg ou le mode Head.'
level-lore: 'Permet de modifier quels éléments de la description du Niveau qui doivent être visibles.'
challenge-lore: 'Permet de modifier quels éléments de la description du Challenge qui doivent être visibles.'
gui-view-mode: 'Permet de définir si le menu du /challenges doit montrer les modes de jeu ou les challenges dans le monde des joueurs.'
history-store: 'Permet d''activer / désactiver le stockage de l''historique des Challenges.'
history-lifespan: 'Permet de modifier le nombre de jours d''enregistrement de l''historique.|0 signifie pour toujours.'
island-store: 'Permet d''activer / désactiver les données stockés des Challenges par île. Cela signifie que les challenges seront les mêmes pour toute l''équipe, si cela est activé.|Cela ne convertira PAS les données au clic. LES PROGRÈS SERONT PERDUS.'
default-locked-icon: 'Permet de changer l''icône de niveau verrouillé par défaut.|Cette option peut être enlevé par chaque niveau.'
gui-mode: 'Permet d''activer / désactiver le menu de Challenge seul|&2Nécessite un redémarrage du serveur.'
click-to-edit: '&4Cliquez ici pour modifier l''entrée.'
edit-text-line: '&6Modifier le message du texte !'
add-text-line: '&6 Ajouter un nouveau message !'
input-mode: 'Basculer entre les modes, chat et enclume (menu).'
title-enable: 'Permet d''activer / désactiver le message de titre qui sera affiché lorsque le joueur aura terminé son challenge.'
title-showtime: 'Permet de modifier la longueur du message que le joueur pourra voir.'
default-import: 'Permet d''importer des challenges par défaut.'
default-export: 'Permet d''exporter les Challenges dans le fichier defaults.json.'
complete-wipe: 'Permet d''effacer complètement toutes les données des Challenges. Inclut les données du joueur!'
current-value: '|&6Valeur actuelle: [value].'
enabled: 'Activé'
disabled: 'Désactivé'
type:
island: '- Type, île:| (permet d''obliger le joueur à avoir certains blocs/mobs autour de lui)'
inventory: '- Type, inventaire:| (permet d''obliger le joueur d''avoir certain items dans son inventaire)'
other: '- Autre type:| (permet d''obliger autre chose depuis d''autres plugins/addons)'
the-end: '- The End'
nether: '- Nether'
normal: '- Overworld'
entity: '- [entity] : [count]'
block: '- [block] : [count]'
permission: '- [permission]'
item: '- [count] x [item]'
item-meta: ' ([meta])'
item-enchant: ' - [enchant] [level]'
command: '- [command]'
level-unlocked: '&fCliquez pour regarder les challenges : [level]'
level-locked: '&fComplétez [count] challenges [level] pour débloquer ce niveau !'
challenge-description:
level: '&fNiveau: [level]'
completed: '&bCompletés'
completed-times-of: 'Complété [donetimes]/[maxtimes] fois'
maxed-reached: 'Complété [donetimes]/[maxtimes] fois'
completed-times: 'Complété [donetimes] fois'
warning-items-take: '&cLes objets requis seront enlevés de votre inventaire !'
objects-close-by: '&cTous les blocs et entités requis doivent être proches de vous sur votre île !'
warning-entities-kill: '&cToutes les entités requises seront tuées lorsque vous aurez terminé ce Challenge !'
warning-blocks-remove: '&cTous les blocs requis seront supprimés lorsque vous aurez terminé ce Challenge. !'
not-repeatable: '&cCe challenge n''est pas répétable !'
experience-reward: '&6Récompense en XP: [value]'
money-reward: '&6Récompense: [value]$'
required-experience: '&6XP requis: [value]'
required-money: '&6Monnaie requise: [value]$'
required-island-level: '&6Niveau d''île requis: [value]'
environment: 'Environement requis:'
reward-items: '&6Récompenses:'
reward-commands: '&6Récompenses (commandes):'
required-items: 'Items requis:'
required-entities: 'Entitiés requises:'
required-blocks: 'Blocs requis:'
level-description:
completed: '&BComplété'
completed-challenges-of: '&3Vous avez complété [number] sur [max] Challenges dans ce niveau.'
waver-amount: '&6Vous pouvez sauter [value] de ce Challenge pour débloquer le niveau suivant.'
experience-reward: '&6Récompense en XP: [value]'
money-reward: '&6Récompense: [value]$'
reward-items: '&6Récompenses:'
reward-commands: '&6Récompenses (commandes):'
titles:
# Title and subtitle my contain variable in [] that will be replaced with proper message from challenge object.
# [friendlyName] will be replaced with challenge friendly name.
# [level] will be replaced with level friendly name.
# [rewardText] will be replaced with challenge reward text.
challenge-title: 'Complété avec succès'
challenge-subtitle: '[friendlyName]'
# Title and subtitle my contain variable in [] that will be replaced with proper message from level object.
# [friendlyName] will be replaced with level friendly name.
# [rewardText] will be replaced with level reward text.
level-title: 'Complété avec succès'
level-subtitle: '[friendlyName]'
messages:
admin:
hit-things: 'Taper des choses pour les ajouter à la liste des choses requises. Faites un clic droit lorsque vous avez terminé.'
you-added: 'Vous avez ajouter [thing] dans le challenge'
challenge-created: '[challenge]&r crée !'
complete-wipe: '&cJ''espère que vous aurez des sauvegardes, car vous venez de vider toutes les données !'
you-completed-challenge: '&2Vous avez complété le challenge: [value] !'
you-repeated-challenge: '&2Vous avez répété le challenge: [value] !'
you-repeated-challenge-multiple: '&2Vous avez répété le challenge: [value] &r&2 [count] fois !'
you-completed-level: '&2Vous avez complété le niveau: [value] !'
name-has-completed-challenge: '&5[name] a complété le challenge: [value] !'
name-has-completed-level: '&5[name] a complété le niveau: [value] !'
import-levels: 'Importer les Niveau'
import-challenges: 'Importer les Challenges'
no-levels: 'Attention: Aucun niveau est défini dans le fichier challenges.yml'
import-number: '[number] Challenges ont été importés'
load-skipping: '"[value]" existe déjà - ignoré'
load-overwriting: 'Écrasement "[value]"'
load-add: 'Ajout d''un nouveau objet: [value]'
defaults-file-overwrite: 'defaults.json existe. Il sera écrasé.'
defaults-file-completed: 'defaults.json file est rempli de challenges dans [world] !'
errors:
no-name: '&cNom du Challenge manquant'
unknown-challenge: '&cChallenge inconnu'
unique-id: '&cL''UniqueID "[id]" n''est pas valide.'
wrong-icon: '&cLe matériau "[value]" n''est pas valide et ne peut pas être utilisé comme un icône.'
not-valid-integer: '&cLa valeur "[value]" n''est pas valide !|Elle doit être comprise entre [min] et [max].'
not-a-integer: '&cLa valeur "[value]" n''est pas un entier!'
not-deployed: '&cLe Challenge ne peut pas être réalisé !'
not-on-island: '&cVous devez être sur votre île pour faire le Challenge !'
challenge-level-not-available: '&cVous n''avez pas débloqué le niveau pour compléter ce Challenge.'
not-repeatable: '&cCe Challenge n''est pas répétable !'
wrong-environment: '&cVous êtes dans le mauvais environnement !'
not-enough-items: '&cVous n''avez pas assez [items] pour relever ce Challenge !'
not-close-enough: '&cVous devez vous tenir dans un rayon de [number] blocs autour de tous les éléments requis.'
you-still-need: '&cTu as encore besoin [amount] [item]'
missing-addon: '&cImpossible de terminer le Challenge. L''addon ou le plugin requis est manquant.'
incorrect: '&cImpossible de compléter le challenge. Les nécessités sont incorrects'
not-enough-money: '&cIl est nécéssaire d''avoir [value] sur votre compte pour compléter le challenge.'
not-enough-experience: '&cIl est nécessaire d''avoir [value] XP pour compléter le challenge.'
island-level: '&cVotre île doit être niveau [number] pour compléter le challenge.'
import-no-file: '&cLe fichier challenges.yml n''a pas été trouvé !'
no-load: '&cErreur: Impossible de charger le fichier challenges.yml. [message]'
load-error: '&cErreur: Impossible de charger [value].'
no-rank: "&cVous n''avez pas le rang pour le faire."
cannot-remove-items: '&cCertains items ne peuvent pas être supprimer de votre inventaire !'
exist-challenges-or-levels: '&cDans votre monde il existe déjà des challenges. Impossible de continuer !'
defaults-file-exist: '&cdefaults.json existe déja. Utilisez le mode écrasement pour le remplacer !'
defaults-file-error: '&cIl y a une erreur lors de la création du fichier defaults.json ! Regardez la console !'
no-challenges: '&cLes challenges ne sont pas actifs dans le monde actuel !'
no-challenges-admin: '&cLes Challenges ne sont pas actifs dans le monde actuel ! Vous devez utiliser &5/[label] Challenges &cpour ajouter cela !'
missing-level: '&cLe Niveau du Challenge [niveau] n''est pas défini dans la base de données. Il peut y avoir des erreurs !'
protection:
flags:
CHALLENGES_ISLAND_PROTECTION:
description: "&5&oChange qui peut\n&5&ocompléter les Challenges"
name: "Protection de Challenge"
CHALLENGES_WORLD_PROTECTION:
description: "&5&oCela permet d''activer / désactiver\n&5&oles prérequis pour les joueurs de\n&5&oqui doivent être sur leur île pour\n&5&ocompléter le Challenge."
name: "Limite de Challenge sur l''île "
hint: "Aucun Challenge en dehors de l''île"
version: 11

View File

@ -148,6 +148,7 @@ challenges:
title-showtime: 'Virsrakta rādīšanas ilgums'
default-import: 'Importēt standarta Uzdevumus'
default-export: 'Exportēt esošos Uzdevumus'
complete-wipe: 'Iztīrīt datubāzes'
next: 'Nākošā'
previous: 'Iepriekšējā'
return: 'Atgriezties'
@ -243,6 +244,7 @@ challenges:
title-showtime: 'Ļauj mainīt cik ilgi virsraksts spēlētājam būs redzams.'
default-import: 'Ļauj ielādēt sākotnējos uzdevumus.'
default-export: 'Ļauj eksportēt uzdevumus uz defaults.json failu.'
complete-wipe: 'Ļauj pilnībā iztīrīt papildinājuma datubāzes. Ieskaitot spēlētāju datus!'
current-value: '|&6Šī brīža vērtība: [value].'
enabled: 'Aktīvs'
disabled: 'Neaktīvs'
@ -307,6 +309,7 @@ challenges:
messages:
admin:
challenge-created: '[challenge]&r izveidots!'
complete-wipe: '&cCerams, ka tev ir saglabātas rezerves kopijas, jo tu tikko iztīrīji visas šī papildinājuma datubāzes!'
you-completed-challenge: '&2Tu izpildīji [value] &r&2uzdevumu!'
you-repeated-challenge: '&2Tu atkārtoji [value] &r&2uzdevumu!'
you-repeated-challenge-multiple: '&2Tu atkārtoji [value] &r&2uzdevumu [count] reizes!'
@ -351,6 +354,7 @@ challenges:
defaults-file-exist: '&cdefaults.json jau eksistē. Lieto overwrite, lai to pārrakstītu!'
defaults-file-error: '&cRadās kļūda veidojot defaults.json failu! Pārbaudi konsoli!'
no-challenges: '&cŠajā pasaulē nav izveidoti uzdevumi!'
no-challenges-admin: '&cŠajā pasaulē nav izveidoti uzdevumi! Izmanot komandu &5/[label] challenges&c, lai tos pievienotu!'
missing-level: '&cLīmenis [level] nav definēts datubāzē. Tas var radīt problēmas!'
protection:
flags:

View File

@ -56,6 +56,11 @@ public class TryToCompleteTest {
*/
@Before
public void setUp() throws Exception {
Server server = mock(Server.class);
PowerMockito.mockStatic(Bukkit.class);
when(Bukkit.getServer()).thenReturn(server);
when(Bukkit.getBukkitVersion()).thenReturn("1.13.2");
user = mock(User.class);
inv = mock(PlayerInventory.class);
when(inv.getContents()).thenReturn(stacks);
@ -63,7 +68,6 @@ public class TryToCompleteTest {
addon = mock(ChallengesAddon.class);
required = new ArrayList<>();
Server server = mock(Server.class);
ItemFactory itemFactory = mock(ItemFactory.class);
when(server.getItemFactory()).thenReturn(itemFactory);
@ -71,9 +75,6 @@ public class TryToCompleteTest {
when(itemFactory.getItemMeta(any())).thenReturn(null);
when(itemFactory.equals(null, null)).thenReturn(true);
PowerMockito.mockStatic(Bukkit.class);
when(Bukkit.getServer()).thenReturn(server);
when(Bukkit.getItemFactory()).thenReturn(itemFactory);
when(Bukkit.getLogger()).thenReturn(Logger.getAnonymousLogger());
}