Add Planner selection to ignore cooldown after repeat cycle, fixes #1244

This commit is contained in:
PikaMug 2020-07-24 05:03:53 -04:00
parent 30ee2997c2
commit 08b1c453f0
8 changed files with 188 additions and 68 deletions

View File

@ -20,6 +20,7 @@ public class Planner {
public String end = null;
public long repeat = -1;
public long cooldown = -1;
public boolean override = false;
public String getStart() {
return start;
@ -81,4 +82,10 @@ public class Planner {
public void setCooldown(long cooldown) {
this.cooldown = cooldown;
}
public boolean getOverride() {
return override;
}
public void setOverride(boolean override) {
this.override = override;
}
}

View File

@ -263,6 +263,7 @@ public class QuestFactory implements ConversationAbandonedListener {
if (pln.getCooldown() != -1) {
context.setSessionData(CK.PLN_COOLDOWN, pln.getCooldown());
}
context.setSessionData(CK.PLN_OVERRIDE, pln.getOverride());
Options opt = q.getOptions();
context.setSessionData(CK.OPT_ALLOW_COMMANDS, opt.getAllowCommands());
context.setSessionData(CK.OPT_ALLOW_QUITTING, opt.getAllowQuitting());
@ -906,6 +907,8 @@ public class QuestFactory implements ConversationAbandonedListener {
? ((Long) context.getSessionData(CK.PLN_REPEAT_CYCLE) / 1000) : null);
pln.set("cooldown", context.getSessionData(CK.PLN_COOLDOWN) != null
? ((Long) context.getSessionData(CK.PLN_COOLDOWN) / 1000) : null);
pln.set("override", context.getSessionData(CK.PLN_OVERRIDE) != null
? (Boolean) context.getSessionData(CK.PLN_OVERRIDE) : null);
if (pln.getKeys(false).isEmpty()) {
section.set("planner", null);
}

View File

@ -450,16 +450,17 @@ public class Quester {
if (preEvent.isCancelled()) {
return;
}
OfflinePlayer player = getOfflinePlayer();
final OfflinePlayer player = getOfflinePlayer();
if (player.isOnline()) {
Player p = getPlayer();
Planner pln = q.getPlanner();
long start = pln.getStartInMillis(); // Start time in milliseconds since UTC epoch
long end = pln.getEndInMillis(); // End time in milliseconds since UTC epoch
long duration = end - start; // How long the quest can be active for
long repeat = pln.getRepeat(); // Length to wait in-between start times
final Player p = getPlayer();
final Planner pln = q.getPlanner();
final long currentTime = System.currentTimeMillis();
final long start = pln.getStartInMillis(); // Start time in milliseconds since UTC epoch
final long end = pln.getEndInMillis(); // End time in milliseconds since UTC epoch
final long duration = end - start; // How long the quest can be active for
final long repeat = pln.getRepeat(); // Length to wait in-between start times
if (start != -1) {
if (System.currentTimeMillis() < start) {
if (currentTime < start) {
String early = Lang.get("plnTooEarly");
early = early.replace("<quest>", ChatColor.AQUA + q.getName() + ChatColor.YELLOW);
early = early.replace("<time>", ChatColor.DARK_PURPLE
@ -469,7 +470,7 @@ public class Quester {
}
}
if (end != -1 && repeat == -1) {
if (System.currentTimeMillis() > end) {
if (currentTime > end) {
String late = Lang.get("plnTooLate");
late = late.replace("<quest>", ChatColor.AQUA + q.getName() + ChatColor.RED);
late = late.replace("<time>", ChatColor.DARK_PURPLE
@ -480,51 +481,46 @@ public class Quester {
}
if (repeat != -1 && start != -1 && end != -1) {
// Ensure that we're past the initial duration
if (System.currentTimeMillis() > end) {
Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() {
@Override
public void run() {
final int maxSize = 2;
final LinkedHashMap<Long, Long> cache = new LinkedHashMap<Long, Long>() {
private static final long serialVersionUID = 3046838061019897713L;
if (currentTime > end) {
final int maxSize = 2;
final LinkedHashMap<Long, Long> cache = new LinkedHashMap<Long, Long>() {
private static final long serialVersionUID = 3046838061019897713L;
@Override
protected boolean removeEldestEntry(final Map.Entry<Long, Long> eldest) {
return size() > maxSize;
}
};
// Store both the upcoming and most recent period of activity
long nextStart = start;
long nextEnd = end;
while (System.currentTimeMillis() >= nextStart) {
nextStart += repeat;
nextEnd = nextStart + duration;
cache.put(nextStart, nextEnd);
}
// Check whether the quest is currently active
boolean active = false;
for (Entry<Long, Long> startEnd : cache.entrySet()) {
if (startEnd.getKey() <= System.currentTimeMillis() && System.currentTimeMillis()
< startEnd.getValue()) {
active = true;
}
}
// If quest is not active, inform user of wait time
if (!active) {
final String early = Lang.get("plnTooEarly")
.replace("<quest>", ChatColor.AQUA + q.getName() + ChatColor.YELLOW)
.replace("<time>", ChatColor.DARK_PURPLE
+ MiscUtil.getTime(nextStart - System.currentTimeMillis()) + ChatColor.YELLOW);
if (p.isOnline()) {
p.sendMessage(ChatColor.YELLOW + early);
}
return;
}
@Override
protected boolean removeEldestEntry(final Map.Entry<Long, Long> eldest) {
return size() > maxSize;
}
});
};
// Store both the upcoming and most recent period of activity
long nextStart = start;
long nextEnd = end;
while (currentTime >= nextStart) {
nextStart += repeat;
nextEnd = nextStart + duration;
cache.put(nextStart, nextEnd);
}
// Check whether the quest is currently active
boolean active = false;
for (Entry<Long, Long> startEnd : cache.entrySet()) {
if (startEnd.getKey() <= currentTime && currentTime < startEnd.getValue()) {
active = true;
}
}
// If quest is not active, or new period of activity should override player cooldown, inform user
if (!active || (q.getPlanner().getOverride() && getCompletedTimes().containsKey(q.getName())
&& currentTime < (getCompletedTimes().get(q.getName()) + duration))) {
if (p.isOnline()) {
final String early = Lang.get("plnTooEarly")
.replace("<quest>", ChatColor.AQUA + q.getName() + ChatColor.YELLOW)
.replace("<time>", ChatColor.DARK_PURPLE
+ MiscUtil.getTime(nextStart - currentTime) + ChatColor.YELLOW);
p.sendMessage(ChatColor.YELLOW + early);
}
return;
}
}
}
}
@ -2819,21 +2815,40 @@ public class Quester {
/**
* Get the difference between Sytem.currentTimeMillis() and the last completed time for a quest
*
* @param q The quest to get the last completed time of
* @param quest The quest to get the last completed time of
* @return Difference between now and then in milliseconds
*/
public long getCooldownDifference(Quest q) {
public long getCompletionDifference(Quest quest) {
long currentTime = System.currentTimeMillis();
long lastTime;
if (completedTimes.containsKey(q.getName()) == false) {
if (completedTimes.containsKey(quest.getName()) == false) {
lastTime = System.currentTimeMillis();
completedTimes.put(q.getName(), System.currentTimeMillis());
completedTimes.put(quest.getName(), System.currentTimeMillis());
} else {
lastTime = completedTimes.get(q.getName());
lastTime = completedTimes.get(quest.getName());
}
long comparator = q.getPlanner().getCooldown();
long difference = (comparator - (currentTime - lastTime));
return difference;
return currentTime - lastTime;
}
/**
* Get the difference between player cooldown and time since last completion of a quest
*
* @deprecated Use {@link #getRemainingCooldown(Quest)}
* @param quest The quest to get the last completed time of
* @return Difference between now and then in milliseconds
*/
public long getCooldownDifference(Quest quest) {
return quest.getPlanner().getCooldown() - getCompletionDifference(quest);
}
/**
* Get the amount of time left before Quester may take a completed quest again
*
* @param quest The quest to calculate the cooldown for
* @return Length of time in milliseconds
*/
public long getRemainingCooldown(Quest quest) {
return quest.getPlanner().getCooldown() - getCompletionDifference(quest);
}
@SuppressWarnings("deprecation")
@ -4100,11 +4115,12 @@ public class Quester {
getPlayer().sendMessage(ChatColor.YELLOW + msg);
}
return false;
} else if (getCompletedQuests().contains(quest.getName()) && getCooldownDifference(quest) > 0) {
} else if (getCompletedQuests().contains(quest.getName()) && getRemainingCooldown(quest) > 0
&& !quest.getPlanner().getOverride()) {
if (giveReason) {
String msg = Lang.get(getPlayer(), "questTooEarly");
msg = msg.replace("<quest>", ChatColor.AQUA + quest.getName() + ChatColor.YELLOW);
msg = msg.replace("<time>", ChatColor.DARK_PURPLE + MiscUtil.getTime(getCooldownDifference(quest))
msg = msg.replace("<time>", ChatColor.DARK_PURPLE + MiscUtil.getTime(getRemainingCooldown(quest))
+ ChatColor.YELLOW);
getPlayer().sendMessage(ChatColor.YELLOW + msg);
}

View File

@ -1174,7 +1174,7 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
if (q.testRequirements(player)) {
available.add(q);
}
} else if (q.getPlanner().hasCooldown() && quester.getCooldownDifference(q) < 0) {
} else if (q.getPlanner().hasCooldown() && quester.getRemainingCooldown(q) < 0) {
if (q.testRequirements(player)) {
available.add(q);
}
@ -1900,6 +1900,9 @@ public class Quests extends JavaPlugin implements ConversationAbandonedListener
throw new QuestFormatException("Requirement cooldown is not a number", questKey);
}
}
if (config.contains("quests." + questKey + ".planner.override")) {
pln.setOverride(config.getBoolean("quests." + questKey + ".planner.override"));
}
}
private void loadQuestOptions(FileConfiguration config, ConfigurationSection questsSection, Quest quest,

View File

@ -137,11 +137,11 @@ public class NpcOfferQuestPrompt extends StringPrompt {
} else if (quester.getCompletedQuests().contains(q.getName())) {
if (quester.getCurrentQuests().size() < plugin.getSettings().getMaxQuests()
|| plugin.getSettings().getMaxQuests() < 1) {
if (quester.getCooldownDifference(q) > 0) {
if (quester.getRemainingCooldown(q) > 0 && !q.getPlanner().getOverride()) {
String early = Lang.get("questTooEarly");
early = early.replace("<quest>", ChatColor.AQUA + q.getName() + ChatColor.YELLOW);
early = early.replace("<time>", ChatColor.DARK_PURPLE
+ MiscUtil.getTime(quester.getCooldownDifference(q)) + ChatColor.YELLOW);
+ MiscUtil.getTime(quester.getRemainingCooldown(q)) + ChatColor.YELLOW);
player.sendMessage(ChatColor.YELLOW + early);
} else if (q.getPlanner().getCooldown() < 0) {
String completed = Lang.get("questAlreadyCompleted");

View File

@ -18,6 +18,7 @@ import java.util.Calendar;
import java.util.Locale;
import java.util.TimeZone;
import me.blackvein.quests.Planner;
import me.blackvein.quests.Quests;
import me.blackvein.quests.convo.quests.QuestsEditorNumericPrompt;
import me.blackvein.quests.convo.quests.QuestsEditorStringPrompt;
@ -40,7 +41,7 @@ public class PlannerPrompt extends QuestsEditorNumericPrompt {
this.plugin = (Quests)context.getPlugin();
}
private final int size = 5;
private final int size = 6;
public int getSize() {
return size;
@ -53,7 +54,6 @@ public class PlannerPrompt extends QuestsEditorNumericPrompt {
public ChatColor getNumberColor(ConversationContext context, int number) {
switch (number) {
case 1:
return ChatColor.BLUE;
case 2:
return ChatColor.BLUE;
case 3:
@ -63,8 +63,9 @@ public class PlannerPrompt extends QuestsEditorNumericPrompt {
return ChatColor.BLUE;
}
case 4:
return ChatColor.BLUE;
case 5:
return ChatColor.BLUE;
case 6:
return ChatColor.GREEN;
default:
return null;
@ -86,6 +87,8 @@ public class PlannerPrompt extends QuestsEditorNumericPrompt {
case 4:
return ChatColor.YELLOW + Lang.get("plnCooldown");
case 5:
return ChatColor.YELLOW + Lang.get("plnOverride");
case 6:
return ChatColor.YELLOW + Lang.get("done");
default:
return null;
@ -127,6 +130,18 @@ public class PlannerPrompt extends QuestsEditorNumericPrompt {
+ ChatColor.RESET + ChatColor.YELLOW + ")";
}
case 5:
if (context.getSessionData(CK.PLN_OVERRIDE) == null) {
boolean defaultOpt = new Planner().getOverride();
return ChatColor.GRAY + "(" + (defaultOpt ? ChatColor.GREEN
+ Lang.get(String.valueOf(defaultOpt)) : ChatColor.RED
+ Lang.get(String.valueOf(defaultOpt))) + ChatColor.GRAY + ")";
} else {
boolean quittingOpt = (Boolean) context.getSessionData(CK.PLN_OVERRIDE);
return ChatColor.GRAY + "(" + (quittingOpt ? ChatColor.GREEN
+ Lang.get(String.valueOf(quittingOpt)) : ChatColor.RED
+ Lang.get(String.valueOf(quittingOpt))) + ChatColor.GRAY + ")";
}
case 6:
return "";
default:
return null;
@ -165,6 +180,8 @@ public class PlannerPrompt extends QuestsEditorNumericPrompt {
case 4:
return new PlannerCooldownPrompt(context);
case 5:
return new PlannerOverridePrompt(context);
case 6:
return plugin.getQuestFactory().returnToMenu(context);
default:
return new PlannerPrompt(context);
@ -273,6 +290,78 @@ public class PlannerPrompt extends QuestsEditorNumericPrompt {
}
}
public class PlannerOverridePrompt extends QuestsEditorStringPrompt {
public PlannerOverridePrompt(ConversationContext context) {
super(context);
}
private final int size = 4;
public int getSize() {
return size;
}
@Override
public String getTitle(ConversationContext context) {
return null;
}
@Override
public String getQueryText(ConversationContext context) {
String text = "Select '<true>' or '<false>'";
text = text.replace("<true>", Lang.get("true"));
text = text.replace("<false>", Lang.get("false"));
return text;
}
public String getSelectionText(ConversationContext context, int number) {
switch (number) {
case 1:
return ChatColor.YELLOW + Lang.get("true");
case 2:
return ChatColor.YELLOW + Lang.get("false");
case 3:
return ChatColor.RED + Lang.get("cmdClear");
case 4:
return ChatColor.RED + Lang.get("cmdCancel");
default:
return null;
}
}
@Override
public String getPromptText(ConversationContext context) {
QuestsEditorPostOpenStringPromptEvent event = new QuestsEditorPostOpenStringPromptEvent(context, this);
context.getPlugin().getServer().getPluginManager().callEvent(event);
String text = Lang.get("optBooleanPrompt");
text = text.replace("<true>", Lang.get("true"));
text = text.replace("<false>", Lang.get("false"));
return ChatColor.YELLOW + text;
}
@Override
public Prompt acceptInput(ConversationContext context, String input) {
if (input.equalsIgnoreCase(Lang.get("cmdCancel")) == false
&& input.equalsIgnoreCase(Lang.get("cmdClear")) == false) {
if (input.startsWith("t") || input.equalsIgnoreCase(Lang.get("true"))
|| input.equalsIgnoreCase(Lang.get("yesWord"))) {
context.setSessionData(CK.PLN_OVERRIDE, true);
} else if (input.startsWith("f") || input.equalsIgnoreCase(Lang.get("false"))
|| input.equalsIgnoreCase(Lang.get("noWord"))) {
context.setSessionData(CK.PLN_OVERRIDE, false);
} else {
context.getForWhom().sendRawMessage(ChatColor.RED + Lang.get("itemCreateInvalidInput"));
return new PlannerOverridePrompt(context);
}
} else if (input.equalsIgnoreCase(Lang.get("cmdClear"))) {
context.setSessionData(CK.PLN_OVERRIDE, null);
return new PlannerPrompt(context);
}
return new PlannerPrompt(context);
}
}
private String getPrettyDate(String formattedDate) {
Calendar cal = Calendar.getInstance();
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");

View File

@ -138,6 +138,7 @@ public class CK {
public static final String PLN_END_DATE = "endDatePln";
public static final String PLN_REPEAT_CYCLE = "repeatCyclePln";
public static final String PLN_COOLDOWN = "cooldownPln";
public static final String PLN_OVERRIDE = "overridePln";
// Options
public static final String OPT_ALLOW_COMMANDS = "allowCommandsOpt";
public static final String OPT_ALLOW_QUITTING = "allowQuittingOpt";

View File

@ -469,6 +469,7 @@ plnStart: "Set start date"
plnEnd: "Set end date"
plnRepeat: "Set repeat cycle"
plnCooldown: "Set player cooldown"
plnOverride: "Ignore cooldown after repeat"
plnTooEarly: "<quest> will be active in <time>."
plnTooLate: "<quest> was last active <time> ago."
optGeneral: "General"