mirror of
https://github.com/BentoBoxWorld/Challenges.git
synced 2024-12-29 04:18:05 +01:00
Implement timeout respecting in challenges completion.
Implement timeout in GUI's. Relates #71
This commit is contained in:
parent
1b01995546
commit
bb5e861b30
@ -251,13 +251,25 @@ public class ChallengesPlayerData implements DataObject
|
||||
* @param challengeName - unique challenge name
|
||||
* @param times - the number of times to set
|
||||
*/
|
||||
public void setChallengeTimes(@NonNull String challengeName, @NonNull int times)
|
||||
public void setChallengeTimes(@NonNull String challengeName, int times)
|
||||
{
|
||||
challengeStatus.put(challengeName, times);
|
||||
challengesTimestamp.put(challengeName, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets last completion time.
|
||||
*
|
||||
* @param challengeName the unique id
|
||||
* @return the last completion time
|
||||
*/
|
||||
public long getLastCompletionTime(@NonNull String challengeName)
|
||||
{
|
||||
return this.challengesTimestamp.getOrDefault(challengeName, 0L);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if a challenge has been done
|
||||
*
|
||||
|
@ -1397,6 +1397,43 @@ public class ChallengesManager
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method returns if given user breached timeout for given challenge.
|
||||
* @param user - User that must be checked.
|
||||
* @param world - World where challenge operates.
|
||||
* @param challenge - Challenge that must be checked.
|
||||
* @return True, if challenge is breached timeout, otherwise - false.
|
||||
*/
|
||||
public boolean isBreachingTimeOut(User user, World world, Challenge challenge)
|
||||
{
|
||||
if (challenge.getTimeout() <= 0)
|
||||
{
|
||||
// Challenge does not have a timeout.
|
||||
return false;
|
||||
}
|
||||
|
||||
return System.currentTimeMillis() <
|
||||
this.getLastCompletionDate(user, world, challenge) + challenge.getTimeout();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets last completion date for given challenge.
|
||||
*
|
||||
* @param user the user
|
||||
* @param world the world
|
||||
* @param challenge the challenge
|
||||
* @return the last completion date
|
||||
*/
|
||||
public long getLastCompletionDate(User user, World world, Challenge challenge)
|
||||
{
|
||||
String userId = this.getDataUniqueID(user, Util.getWorld(world));
|
||||
this.addPlayerData(userId);
|
||||
|
||||
return this.playerCacheData.get(userId).getLastCompletionTime(challenge.getUniqueId());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method sets given challenge as completed.
|
||||
* @param user - Targeted user.
|
||||
|
@ -13,6 +13,7 @@ import org.bukkit.inventory.ItemStack;
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import java.time.*;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -159,13 +160,17 @@ public abstract class CommonPanel
|
||||
String requirements = isCompletedAll ? "" : this.generateRequirements(challenge, target);
|
||||
// Get rewards in single string
|
||||
String rewards = isCompletedAll ? "" : this.generateRewards(challenge, isCompletedOnce);
|
||||
// Get coolDown in singe string
|
||||
String coolDown = isCompletedAll || challenge.getTimeout() <= 0 ? "" :
|
||||
this.generateCoolDown(challenge, target);
|
||||
|
||||
if (!description.replaceAll("(?m)^[ \\t]*\\r?\\n", "").isEmpty())
|
||||
{
|
||||
String returnString = this.user.getTranslationOrNothing(reference + "lore",
|
||||
"[requirements]", requirements,
|
||||
"[rewards]", rewards,
|
||||
"[status]", status);
|
||||
"[status]", status,
|
||||
"[cooldown]", coolDown);
|
||||
|
||||
// remove empty lines from the generated text.
|
||||
List<String> collect =
|
||||
@ -191,7 +196,8 @@ public abstract class CommonPanel
|
||||
Constants.PARAMETER_DESCRIPTION, description,
|
||||
"[requirements]", requirements,
|
||||
"[rewards]", rewards,
|
||||
"[status]", status);
|
||||
"[status]", status,
|
||||
"[cooldown]", coolDown);
|
||||
|
||||
// Remove empty lines and returns as a list.
|
||||
|
||||
@ -202,6 +208,43 @@ public abstract class CommonPanel
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate cool down string.
|
||||
*
|
||||
* @param challenge the challenge
|
||||
* @param target the target
|
||||
* @return the string
|
||||
*/
|
||||
private String generateCoolDown(Challenge challenge, @Nullable User target)
|
||||
{
|
||||
final String reference = Constants.DESCRIPTIONS + "challenge.cooldown.";
|
||||
|
||||
String coolDown;
|
||||
|
||||
if (target != null && this.manager.isBreachingTimeOut(target, this.world, challenge))
|
||||
{
|
||||
long missing = this.manager.getLastCompletionDate(this.user, this.world, challenge) +
|
||||
challenge.getTimeout() - System.currentTimeMillis();
|
||||
|
||||
coolDown = this.user.getTranslation(reference + "wait-time",
|
||||
"[time]",
|
||||
Utils.parseDuration(Duration.ofMillis(missing), this.user));
|
||||
}
|
||||
else
|
||||
{
|
||||
coolDown = "";
|
||||
}
|
||||
|
||||
String timeout = this.user.getTranslation(reference + "timeout",
|
||||
"[time]",
|
||||
Utils.parseDuration(Duration.ofMillis(challenge.getTimeout()), this.user));
|
||||
|
||||
return this.user.getTranslation(reference + "lore",
|
||||
"[timeout]", timeout,
|
||||
"[wait-time]", coolDown);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method generate requirements description for given challenge.
|
||||
* @param challenge Challenge which requirements must be generated.
|
||||
|
@ -303,6 +303,12 @@ public class ChallengesPanel extends CommonPanel
|
||||
this.createChallengeButton(template, challenge).getItem());
|
||||
}
|
||||
}
|
||||
else if (challenge.isRepeatable() && challenge.getTimeout() > 0)
|
||||
{
|
||||
// Update timeout after clicking.
|
||||
panel.getInventory().setItem(i,
|
||||
this.createChallengeButton(template, challenge).getItem());
|
||||
}
|
||||
break;
|
||||
case "COMPLETE_MAX":
|
||||
if (challenge.isRepeatable())
|
||||
@ -328,6 +334,12 @@ public class ChallengesPanel extends CommonPanel
|
||||
this.createChallengeButton(template, challenge).getItem());
|
||||
}
|
||||
}
|
||||
else if (challenge.getTimeout() > 0)
|
||||
{
|
||||
// Update timeout after clicking.
|
||||
panel.getInventory().setItem(i,
|
||||
this.createChallengeButton(template, challenge).getItem());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "MULTIPLE_PANEL":
|
||||
|
@ -3,6 +3,8 @@ package world.bentobox.challenges.tasks;
|
||||
|
||||
|
||||
import com.google.common.collect.UnmodifiableIterator;
|
||||
import java.time.*;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
@ -228,7 +230,8 @@ public class TryToComplete
|
||||
int maxTimes)
|
||||
{
|
||||
return new TryToComplete(addon, user, challenge, world, topLabel, permissionPrefix).
|
||||
build(maxTimes).meetsRequirements;
|
||||
build(maxTimes).
|
||||
meetsRequirements;
|
||||
}
|
||||
|
||||
|
||||
@ -713,6 +716,17 @@ public class TryToComplete
|
||||
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.not-repeatable"));
|
||||
result = EMPTY_RESULT;
|
||||
}
|
||||
// Check if timeout is not broken
|
||||
else if (this.manager.isBreachingTimeOut(this.user, this.world, this.challenge))
|
||||
{
|
||||
long missing = this.manager.getLastCompletionDate(this.user, this.world, challenge) +
|
||||
this.challenge.getTimeout() - System.currentTimeMillis();
|
||||
|
||||
Utils.sendMessage(this.user, this.user.getTranslation("challenges.errors.timeout",
|
||||
"[timeout]", Utils.parseDuration(Duration.ofMillis(this.challenge.getTimeout()), this.user),
|
||||
"[wait-time]", Utils.parseDuration(Duration.ofMillis(missing), this.user)));
|
||||
result = EMPTY_RESULT;
|
||||
}
|
||||
// Check environment
|
||||
else if (!this.challenge.getEnvironment().isEmpty() &&
|
||||
!this.challenge.getEnvironment().contains(this.user.getWorld().getEnvironment()))
|
||||
@ -776,7 +790,7 @@ public class TryToComplete
|
||||
*/
|
||||
private int getAvailableCompletionTimes(int vantedTimes)
|
||||
{
|
||||
if (!this.challenge.isRepeatable())
|
||||
if (!this.challenge.isRepeatable() || this.challenge.getTimeout() > 0)
|
||||
{
|
||||
// Challenge is not repeatable
|
||||
vantedTimes = 1;
|
||||
@ -1513,7 +1527,7 @@ public class TryToComplete
|
||||
*
|
||||
* @author tastybento
|
||||
*/
|
||||
class ChallengeResult
|
||||
static class ChallengeResult
|
||||
{
|
||||
/**
|
||||
* This method sets that challenge meets all requirements at least once.
|
||||
|
@ -1,6 +1,7 @@
|
||||
package world.bentobox.challenges.utils;
|
||||
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@ -878,4 +879,43 @@ public class Utils
|
||||
"[type]", prettifyObject(itemType, user),
|
||||
"[meta]", meta);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method parses duration to a readable format.
|
||||
* @param duration that needs to be parsed.
|
||||
* @return parsed duration string.
|
||||
*/
|
||||
public static String parseDuration(Duration duration, User user)
|
||||
{
|
||||
final String reference = Constants.DESCRIPTIONS + "challenge.cooldown.";
|
||||
|
||||
String returnString = "";
|
||||
|
||||
if (duration.toDays() > 0)
|
||||
{
|
||||
returnString += user.getTranslationOrNothing(reference + "in-days",
|
||||
Constants.PARAMETER_NUMBER, String.valueOf(duration.toDays()));
|
||||
}
|
||||
|
||||
if (duration.toHoursPart() > 0)
|
||||
{
|
||||
returnString += user.getTranslationOrNothing(reference + "in-hours",
|
||||
Constants.PARAMETER_NUMBER, String.valueOf(duration.toHoursPart()));
|
||||
}
|
||||
|
||||
if (duration.toMinutesPart() > 0)
|
||||
{
|
||||
returnString += user.getTranslationOrNothing(reference + "in-minutes",
|
||||
Constants.PARAMETER_NUMBER, String.valueOf(duration.toMinutesPart()));
|
||||
}
|
||||
|
||||
if (duration.toSecondsPart() > 0 || returnString.isBlank())
|
||||
{
|
||||
returnString += user.getTranslationOrNothing(reference + "in-seconds",
|
||||
Constants.PARAMETER_NUMBER, String.valueOf(duration.toSecondsPart()));
|
||||
}
|
||||
|
||||
return returnString;
|
||||
}
|
||||
}
|
||||
|
@ -829,6 +829,7 @@ challenges:
|
||||
lore: |-
|
||||
[description]
|
||||
[status]
|
||||
[cooldown]
|
||||
[requirements]
|
||||
[rewards]
|
||||
# Contains a text generated inside [status] lore
|
||||
@ -841,6 +842,23 @@ challenges:
|
||||
completed-times-of: "&2 Completed &7&l [number] &r&2 out of &7&l [max] &r&2 times"
|
||||
# Status message that indicates that max completion count reached for repeatable challenge
|
||||
completed-times-reached: "&2&l Completed all &7 [max] &2 times"
|
||||
# Contains a text generated inside [cooldown] lore
|
||||
cooldown:
|
||||
lore: |-
|
||||
[timeout]
|
||||
[wait-time]
|
||||
# Text message that shows challenges timeout.
|
||||
timeout: "&7&l Cool down: &r&7 [time]"
|
||||
# Text message that shows challenges wait time if it is larger than 0.
|
||||
wait-time: "&c&l Available after: &r&c [time]"
|
||||
# Text message that replaces days if number > 1
|
||||
in-days: "[number] d, "
|
||||
# Text message that replaces hours if number > 1
|
||||
in-hours: "[number] h, "
|
||||
# Text message that replaces minutes if number > 1
|
||||
in-minutes: "[number] min, "
|
||||
# Text message that replaces seconds if number > 1
|
||||
in-seconds: "[number] s"
|
||||
# Contains a text generated inside [requirements] lore
|
||||
requirements:
|
||||
lore: |-
|
||||
@ -1156,6 +1174,7 @@ challenges:
|
||||
invalid-challenge: "&c Challenge [challenge] contains invalid data. It will not be loaded from database!"
|
||||
no-library-entries: "&c Cannot find any library entries. Nothing to show."
|
||||
not-hooked: "&c Challenges Addon could not find any GameMode."
|
||||
timeout: "&c This challenge requires to wait [timeout] between completions. You must wait [wait-time] till complete it again."
|
||||
# # Showcase for manual material translation
|
||||
# materials:
|
||||
# # Names should be lowercase.
|
||||
|
@ -849,6 +849,7 @@ challenges:
|
||||
lore: |-
|
||||
[description]
|
||||
[status]
|
||||
[cooldown]
|
||||
[requirements]
|
||||
[rewards]
|
||||
# Contains a text generated inside [status] lore
|
||||
@ -861,6 +862,23 @@ challenges:
|
||||
completed-times-of: "&2 Izpildīts &7&l [number] &r&2 no &7&l [max] &r&2 reizēm"
|
||||
# Status message that indicates that max completion count reached for repeatable challenge
|
||||
completed-times-reached: "&2&l Izpildīts visas &7 [max] &2 reizes"
|
||||
# Contains a text generated inside [cooldown] lore
|
||||
cooldown:
|
||||
lore: |-
|
||||
[timeout]
|
||||
[wait-time]
|
||||
# Text message that shows challenges timeout.
|
||||
timeout: "&7&l Taimauts: &r&7 [time]"
|
||||
# Text message that shows challenges wait time if it is larger than 0.
|
||||
wait-time: "&c&l Jānogaida: &r&c [time]"
|
||||
# Text message that replaces days if number > 1
|
||||
in-days: "[number] d, "
|
||||
# Text message that replaces hours if number > 1
|
||||
in-hours: "[number] h, "
|
||||
# Text message that replaces minutes if number > 1
|
||||
in-minutes: "[number] min, "
|
||||
# Text message that replaces seconds if number > 1
|
||||
in-seconds: "[number] s"
|
||||
# Contains a text generated inside [requirements] lore
|
||||
requirements:
|
||||
lore: |-
|
||||
@ -1180,6 +1198,7 @@ challenges:
|
||||
invalid-challenge: "&c Uzdevums [challenge] satur nekorektus datus. Tas var tikt ielādēts nekorekti!"
|
||||
no-library-entries: "&c Nevar atrast bibliotēkas ierakstus. Nav ko rādīt."
|
||||
not-hooked: "&c Uzdevumu Papildinājumam neizdevās atrast Spēles Režīmu."
|
||||
timeout: "&c Šim uzdevumam ir uzstādīts [timeout] taimauts starp izpildēm. Tev vēl ir jāgaida [wait-time], lai varētu pildīt uzdevumu."
|
||||
# # Showcase for manual material translation
|
||||
# materials:
|
||||
# # Names should be lowercase.
|
||||
|
Loading…
Reference in New Issue
Block a user